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.

EclipseCon 2007: Effective Use of the Eclipse Modeling Framework

EclipseCon 2007 half-day tutorial providing an extended introduction to the EMF core, as well as its query, transaction, and validation components.

  • Login to see the comments

EclipseCon 2007: Effective Use of the Eclipse Modeling Framework

  1. 1. Christian W. Damus, Kenn Hussey, Ed Merks and Dave Steinberg IBM Rational Software Ottawa and Toronto, Canada EMF, EMFT, and MDT Projects Effective Use of the Eclipse Modeling Framework
  2. 2. Part 1: Introduction to the Eclipse Modeling Framework
  3. 3. Agenda <ul><li>EMF in a Nutshell </li></ul><ul><li>EMF Components </li></ul><ul><li>The Ecore Metamodel </li></ul><ul><li>Code Generation, Regeneration and Merge </li></ul><ul><li>The EMF Runtime </li></ul><ul><li>Recording Changes </li></ul><ul><li>Validation </li></ul><ul><li>Summary </li></ul>
  4. 4. EMF Demo <ul><li>Quickly generate a working graphical editor to create and manipulate instances of a UML model </li></ul>
  5. 5. What is EMF? <ul><li>A modeling & data integration framework </li></ul><ul><li>Exploits the facilities offered in Eclipse to… </li></ul><ul><ul><li>Generate code without losing user customizations (merge) </li></ul></ul><ul><ul><li>Automate important tasks (such as registering the runtime information) </li></ul></ul><ul><ul><li>Improve extensibility </li></ul></ul><ul><ul><li>Provide a UI layer </li></ul></ul><ul><li>What is an EMF “model”? </li></ul><ul><ul><li>Specification of your application’s data </li></ul></ul><ul><ul><ul><li>Object attributes </li></ul></ul></ul><ul><ul><ul><li>Relationships (associations) between objects </li></ul></ul></ul><ul><ul><ul><li>Operations available on each object </li></ul></ul></ul><ul><ul><ul><li>Simple constraints (eg. cardinality) on objects and relationships </li></ul></ul></ul><ul><ul><li>Essentially it represents the class diagram of the application </li></ul></ul>
  6. 6. What does EMF Provide? <ul><li>From a model specification, EMF can generate efficient, correct, and easily customizable implementation code </li></ul><ul><li>Out of the box, EMF provides support for </li></ul><ul><ul><li>Java ™ interfaces </li></ul></ul><ul><ul><li>UML </li></ul></ul><ul><ul><li>XML Schema </li></ul></ul><ul><li>EMF converts your models to Ecore (EMF metamodel) </li></ul><ul><li>Tooling support within the Eclipse framework (UI, headless mode, Ant and standalone), including support for generating Eclipse-based and RCP editors </li></ul><ul><li>Reflective API and dynamic model definition </li></ul><ul><li>Persistence API with out of box support for XML/XMI (de)serialization of instances of a model </li></ul><ul><li>And much more…. </li></ul>
  7. 7. Why EMF? <ul><li>EMF is middle ground in the modeling vs. programming worlds </li></ul><ul><ul><li>Focus is on class diagram subset of UML modeling (object model) </li></ul></ul><ul><ul><li>Transforms models into Java code </li></ul></ul><ul><ul><li>Provides the infrastructure to use models effectively in your application </li></ul></ul><ul><li>Very low cost of entry </li></ul><ul><ul><li>EMF is free and open source </li></ul></ul><ul><ul><li>Full scale graphical modeling tool not required </li></ul></ul><ul><ul><li>Reuses your knowledge of UML, XML Schema, or Java </li></ul></ul><ul><li>It’s real, proven technology (since 2002) </li></ul>
  8. 8. EMF History <ul><li>First version was released in June, 2002 </li></ul><ul><li>Originally based on MOF (Meta Object Facility) </li></ul><ul><ul><li>From OMG (Object Management Group) </li></ul></ul><ul><ul><li>Abstract language and framework for specifying, constructing, and managing technology neutral metamodels </li></ul></ul><ul><li>EMF evolved based on experience supporting a large set of tools </li></ul><ul><ul><li>Efficient Java implementation of a practical subset of the MOF API </li></ul></ul><ul><li>2003: EMOF defined (Essential MOF) </li></ul><ul><ul><li>Part of OMG’s MOF 2 specification; UML2 based </li></ul></ul><ul><ul><li>EMF is approximately the same functionality </li></ul></ul><ul><ul><ul><li>Significant contributor to the spec; adapting to it </li></ul></ul></ul>
  9. 9. Who is Using EMF Today? <ul><li>Eclipse projects </li></ul><ul><ul><li>Foundation for the Modeling Project: Graphical Modeling Framework (GMF), EMF Ontology Definition Metamodel (EODM), UML2… </li></ul></ul><ul><ul><li>Other uses: Web Tools Platform (WTP), Test and Performance Tools Platform (TPTP), Business Intelligence and Reporting Tools (BIRT), Data Tools Platform (DTP), Visual Editor (VE)… </li></ul></ul><ul><li>Commercial offerings </li></ul><ul><ul><li>IBM, Borland, Oracle, Omondo, Versata, MetaMatrix, Bosch, Ensemble… </li></ul></ul><ul><li>Applied sciences </li></ul><ul><ul><li>Darmstadt University of Technology, Mayo Clinic College of Medicine, European Space Agency… </li></ul></ul><ul><li>Large open source community </li></ul><ul><ul><li>Over 1,000,000 download requests in 2006 </li></ul></ul>
  10. 10. EMF at IBM <ul><li>Pervasive usage across product lines </li></ul><ul><ul><li>IBM ® Rational ® Software Architect </li></ul></ul><ul><ul><li>IBM Rational Application Developer for WebSphere Software </li></ul></ul><ul><ul><li>IBM WebSphere ® Integration Developer </li></ul></ul><ul><ul><li>IBM WebSphere Application Server </li></ul></ul><ul><ul><li>IBM Lotus ® Workplace </li></ul></ul><ul><li>Emerging technology projects: alphaWorks ® </li></ul><ul><ul><li>Emfatic Language for EMF Development ( </li></ul></ul><ul><ul><li>Model Transformation Framework ( </li></ul></ul><ul><ul><li>XML Forms Generator ( </li></ul></ul>
  11. 11. What Have People Said About EMF? <ul><li>EMF represents the core subset that's left when the non-essentials are eliminated. It represents a rock solid foundation upon which the more ambitious extensions of UML and MDA can be built. </li></ul><ul><li>– Vlad Varnica, OMONDO Business Development Director, 2002 </li></ul><ul><li>EMF provides the glue between the modeling and programming worlds , offering an infrastructure to use models effectively in code by integrating UML, XML and Java. EMF thus fits well into [the] Model-Driven Development approach, and is critically important for Model-Driven Architecture , which underpins service-oriented architectures [SOA]. </li></ul><ul><li>– Jason Bloomberg, Senior analyst for XML & Web services, ZapThink, 2003 </li></ul><ul><li>EMF was chosen because it (a) provides a lightweight, pragmatic approach to modeling with very low entry cost and is thus suitable for rapid prototyping, (b) unifies key technologies such as Java and XML, and (c) integrates well into Eclipse. </li></ul><ul><li>– Bruch, Bockisch, Schäefer, Mezini, Darmstadt Univ. of Technology, 2005 </li></ul><ul><li>[As] a consultant with fiduciary responsibility to my customers, [...] given the enormous traction that Eclipse has gathered, we have to view the EMF metadata management framework as the de facto standard . </li></ul><ul><li>– David Frankel, as seen in Business Process Trends, March 2005 </li></ul>
  12. 12. Creating the Ecore Model <ul><li>Representing the modeled domain in Ecore is the first step in using EMF </li></ul><ul><li>Ecore can be created </li></ul><ul><ul><li>Directly using the EMF editors </li></ul></ul><ul><ul><li>Through a graphical UI provided by external contributions </li></ul></ul><ul><ul><li>By converting a model specification for which a Model Importer is available </li></ul></ul><ul><li>Model Importers available in EMF </li></ul><ul><ul><li>Java Interfaces </li></ul></ul><ul><ul><li>UML models expressed in Rational Rose ® files </li></ul></ul><ul><ul><li>XML Schema </li></ul></ul><ul><li>Choose the one matching your perspective or skills </li></ul>
  13. 13. Model Importers Available in EMF <ul><li>Java Interfaces </li></ul>public interface PurchaseOrder { String getShipTo (); void setShipTo(String value); String getBillTo (); void setBillTo(String value); List<Item> getItems (); } public interface Item { String getProductName (); void setProductName(String value); int getQuantity (); void setQuantity(int value) float getPrice (); void setPrice(float value); }
  14. 14. Model Importers Available in EMF <ul><li>UML Class Diagram </li></ul>
  15. 15. Model Importers Available in EMF <ul><li>XML Schema </li></ul><?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?> <xsd:schema xmlns:xsd=&quot;; targetNamespace=&quot;; xmlns:PO=&quot;;> <xsd:complexType name=&quot; PurchaseOrder &quot;> <xsd:sequence> <xsd:element name=&quot; shipTo &quot; type=&quot;xsd:string&quot;/> <xsd:element name=&quot; billTo &quot; type=&quot;xsd:string&quot;/> <xsd:element name=&quot; items &quot; type=&quot;PO:Item&quot; minOccurs=&quot;0&quot; maxOccurs=&quot;unbounded&quot;/> </xsd:sequence> </xsd:complexType> <xsd:complexType name=&quot;Item&quot;> <xsd:sequence> <xsd:element name=&quot; productName &quot; type=&quot;xsd:string&quot;/> <xsd:element name=&quot; quantity &quot; type=&quot;xsd:int&quot;/> <xsd:element name=&quot; price &quot; type=&quot;xsd:float&quot;/> </xsd:sequence> </xsd:complexType> </xsd:schema>
  16. 16. Unifying Java, XML and UML Technologies <ul><li>The Model Importers available in EMF were carefully chosen to integrate today’s most important technologies </li></ul><ul><li>All three forms provide the same information </li></ul><ul><ul><li>Different visualization/representation </li></ul></ul><ul><ul><li>The application’s “model” of the structure </li></ul></ul><ul><li>From a model definition, EMF can generate </li></ul><ul><ul><li>Java implementation code, including UI </li></ul></ul><ul><ul><li>XML Schemas </li></ul></ul><ul><ul><li>Eclipse projects and plug-in </li></ul></ul>
  17. 17. Typical EMF Usage Scenario <ul><li>Create an Ecore model that represents the domain you are working on </li></ul><ul><ul><li>Import UML (e.g. Rose .mdl file) </li></ul></ul><ul><ul><li>Import XML Schema </li></ul></ul><ul><ul><li>Import annotated Java interfaces </li></ul></ul><ul><ul><li>Create Ecore model directly using EMF's Ecore editor or a graphical editor </li></ul></ul><ul><li>Generate Java code for model </li></ul><ul><li>Prime the model with instance data using generated EMF model editor </li></ul><ul><li>Iteratively refine model (and regenerate code) and develop Java application </li></ul><ul><ul><li>You will use the EMF generated code to implement the use cases of your application </li></ul></ul><ul><li>Optionally, use EMF.Edit to build customized user interface </li></ul>
  18. 18. EMF and Java 5.0 <ul><li>EMF 2.3 exploits the capabilities of Java 5.0 </li></ul><ul><ul><li>Generics </li></ul></ul><ul><ul><li>Typesafe enums </li></ul></ul><ul><ul><li>Annotations </li></ul></ul><ul><ul><li>Enhanced for loop </li></ul></ul><ul><ul><li>Autoboxing </li></ul></ul><ul><li>EMF 2.3 provides a 5.0-targeted runtime that can only be run on a Java 5.0 or later VM </li></ul><ul><li>The code generator can also produce application code that runs on a 1.4 VM against the EMF 2.2.x runtime </li></ul><ul><li>This is a recognition that Java 5.0 is the way forward, but the transition need not be painful for the user </li></ul>
  19. 19. EMF and Java 5.0 <ul><li>Want to know more about Java 5.0 and EMF? </li></ul><ul><li>Modeling Generics with Ecore </li></ul><ul><li>Tuesday, 11:10 am </li></ul><ul><li>Grand Ballroom D </li></ul><ul><li>Java 5: A Developer’s Experience </li></ul><ul><li>Thursday, 10:10 am </li></ul><ul><li>Room 203-204 </li></ul>
  20. 20. Agenda <ul><li>EMF in a Nutshell </li></ul><ul><li>EMF Components </li></ul><ul><li>The Ecore Metamodel </li></ul><ul><li>Code Generation, Regeneration and Merge </li></ul><ul><li>The EMF Runtime </li></ul><ul><li>Recording Changes </li></ul><ul><li>Validation </li></ul><ul><li>Summary </li></ul>
  21. 21. EMF Architecture EMF Runtime EMF Tools Core Edit Codegen Model Editor Application Generates Eclipse Platform
  22. 22. EMF Components <ul><li>EMF Core </li></ul><ul><ul><li>Ecore metamodel </li></ul></ul><ul><ul><li>Model change notification & validation </li></ul></ul><ul><ul><li>Persistence and serialization </li></ul></ul><ul><ul><li>Reflection API </li></ul></ul><ul><ul><li>Runtime support for generated models </li></ul></ul><ul><li>EMF Edit </li></ul><ul><ul><li>Helps integrate models with a rich user interface </li></ul></ul><ul><ul><li>Used to build editors and viewers for your model </li></ul></ul><ul><ul><li>Includes default reflective model editor </li></ul></ul><ul><li>EMF Codegen </li></ul><ul><ul><li>Code generator for core and edit based components </li></ul></ul><ul><ul><li>Extensible model importer/exporter framework </li></ul></ul>
  23. 23. EMF Tools: Model Import and Generation <ul><li>Generator Features: </li></ul><ul><li>Customizable JSP-like templates (JET) </li></ul><ul><li>JDT-integrated, command-line, or Ant </li></ul><ul><li>Fully supports regeneration and merge </li></ul>I M P O R T GENERATE Ecore Model UML XML Schema Java model Java model Java edit Java editor* * Eclipse IDE-integrated or RCP-based
  24. 24. EMF Model Importers <ul><li>UML </li></ul><ul><ul><li>Rational Rose .mdl file </li></ul></ul><ul><ul><li>Eclipse UML2 project provides importer for .uml2 </li></ul></ul><ul><li>Annotated Java </li></ul><ul><ul><li>Java interfaces representing modeled classes </li></ul></ul><ul><ul><li>Javadoc annotations using @model tags to express model properties not captured by method declarations </li></ul></ul><ul><ul><li>Lowest cost approach </li></ul></ul><ul><li>XML Schema </li></ul><ul><ul><li>Describes the data of the modeled domain </li></ul></ul><ul><ul><li>Provides richer description of the data, which EMF exploits </li></ul></ul><ul><li>Ecore model (*.ecore file) </li></ul><ul><ul><li>Just creates the generator model (discussed later) </li></ul></ul><ul><ul><li>Also handles EMOF (*.emof) </li></ul></ul>
  25. 25. Ecore Model Creation <ul><li>An Ecore model is created within an Eclipse project via a wizard </li></ul><ul><li>Input: one of the model specifications from the previous slide </li></ul><ul><li>Output: </li></ul><ul><ul><li>modelname.ecore </li></ul></ul><ul><ul><ul><li>Ecore model file in XMI format </li></ul></ul></ul><ul><ul><ul><li>Canonical form of the model </li></ul></ul></ul><ul><ul><li>modelname.genmodel </li></ul></ul><ul><ul><ul><li>A “generator model” for specifying generator options </li></ul></ul></ul><ul><ul><ul><li>Contains decorators for Ecore model elements, providing details that would otherwise pollute the model (e.g. target directories for code generation) </li></ul></ul></ul><ul><ul><ul><li>EMF code generator is an EMF .genmodel editor </li></ul></ul></ul><ul><ul><ul><li>Automatically kept in synch with .ecore file </li></ul></ul></ul>
  26. 26. Ecore Model Editor <ul><li>A generated (and customized) EMF editor for the Ecore model </li></ul><ul><li>Create, delete, etc. model elements (EClass, EAttribute, EReference, etc.) using pop-up actions in the editor's tree </li></ul><ul><li>Set names, etc. in the Properties view </li></ul>
  27. 27. Ecore Model Editor <ul><li>A graphical editor is a better approach </li></ul><ul><ul><li>GMF Ecore Diagram Example ( </li></ul></ul><ul><ul><li>Omondo EclipseUML ( </li></ul></ul>
  28. 28. EMF Generator <ul><li>Similar layout to Ecore model editor </li></ul><ul><li>Automatically keeps in synch with .ecore changes </li></ul><ul><li>Generate code with pop-up menu actions </li></ul><ul><ul><li>Generate Model Code </li></ul></ul><ul><ul><li>Generate Edit Code </li></ul></ul><ul><ul><li>Generate Editor Code </li></ul></ul><ul><ul><li>Generate Test Code </li></ul></ul><ul><ul><li>Generate All </li></ul></ul><ul><li>Code generation options in Properties view </li></ul><ul><li>Generator > Reload to reload .genmodel and .ecore files from original model form </li></ul>
  29. 29. Agenda <ul><li>EMF in a Nutshell </li></ul><ul><li>EMF Components </li></ul><ul><li>The Ecore Metamodel </li></ul><ul><li>Code Generation, Regeneration and Merge </li></ul><ul><li>The EMF Runtime </li></ul><ul><li>Recording Changes </li></ul><ul><li>Validation </li></ul><ul><li>Summary </li></ul>
  30. 30. The Ecore (Meta) Model <ul><li>Ecore is EMF's model of a model </li></ul><ul><ul><li>Also called a “metamodel” </li></ul></ul><ul><ul><li>Persistent representation is XMI </li></ul></ul>
  31. 31. The Ecore Metamodel
  32. 32. Partial List of Ecore Data Types <ul><li>Ecore data types are serializable and custom data types are supported </li></ul>java.lang.Float EFloatObject java.lang.Object EJavaObject java.lang.Boolean EBooleanObject byte[ ] EByteArray java.lang.String EString float EFloat char EChar boolean EBoolean Java Primitive Type or Class Ecore Data Type
  33. 33. Ecore Model for Purchase Orders is represented in Ecore as
  34. 34. Purchase Order Ecore XMI <ul><li>Alternate serialization format is EMOF (Essential MOF) XMI </li></ul><ul><ul><li>Part of OMG Meta Object Facility (MOF) 2.0 standard ( </li></ul></ul><eClassifiers xsi:type=&quot;ecore:EClass&quot; name=&quot; PurchaseOrder &quot;> <eReferences name=&quot; items &quot; eType=&quot;#//Item&quot; upperBound=&quot;-1&quot; containment=&quot;true&quot;/> <eAttributes name=&quot; shipTo &quot; eType=&quot;ecore:EDataType http:...Ecore#//EString&quot;/> <eAttributes name=&quot; billTo &quot; eType=&quot;ecore:EDataType http:...Ecore#//EString&quot;/> </eClassifiers>
  35. 35. Agenda <ul><li>EMF in a Nutshell </li></ul><ul><li>EMF Components </li></ul><ul><li>The Ecore Metamodel </li></ul><ul><li>Code Generation, Regeneration and Merge </li></ul><ul><li>The EMF Runtime </li></ul><ul><li>Recording Changes </li></ul><ul><li>Validation </li></ul><ul><li>Summary </li></ul>
  36. 36. Code Generation <ul><li>EMF framework is lightweight </li></ul><ul><ul><li>Generated code is clean, simple, efficient </li></ul></ul><ul><li>EMF can generate </li></ul><ul><ul><li>Model implementation </li></ul></ul><ul><ul><li>UI-independent edit support </li></ul></ul><ul><ul><li>Editor and views for Eclipse IDE-integrated or RCP application </li></ul></ul><ul><ul><li>JUnit test skeletons </li></ul></ul><ul><ul><li>Manifests, plug-in classes, properties, icons, etc. </li></ul></ul>
  37. 37. Generated Model Code <ul><li>Interface and implementation for each modeled class </li></ul><ul><ul><li>Includes get/set accessors for attributes and references </li></ul></ul><ul><ul><li>Usage example </li></ul></ul>public interface PurchaseOrder extends EObject { String getShipTo (); void setShipTo (String value); String getBillTo (); void setBillTo (String value); EList<Item> getItems (); } order .getItems().add( item );
  38. 38. Generated Model Code <ul><li>Factory to create instances of model objects </li></ul><ul><li>Package class provides access to metadata </li></ul><ul><li>Also generated: switch utility, adapter factory base, validator, custom resource, XML processor </li></ul>POFactory factory = POFactory.eINSTANCE ; PurchaseOrder order = factory .createPurchaseOrder(); POPackage poPackage = POPackage.eINSTANCE ; EClass itemClass = poPackage. getItem (); //or POPackage.Literals.ITEM EAttribute priceAttr = poPackage. getItem_Price (); //or itemClass.getEStructuralFeature( POPackage.ITEM__PRICE ) //or POPackage.Literals.ITEM__PRICE
  39. 39. Generated Edit/Editor Code <ul><li>Viewing/editing code divided into two parts </li></ul><ul><ul><li>UI-independent code </li></ul></ul><ul><ul><ul><li>Item providers (adapters) </li></ul></ul></ul><ul><ul><ul><li>Item provider adapter factory </li></ul></ul></ul><ul><ul><li>UI-dependent code </li></ul></ul><ul><ul><ul><li>Model creation wizard </li></ul></ul></ul><ul><ul><ul><li>Editor </li></ul></ul></ul><ul><ul><ul><li>Action bar contributor </li></ul></ul></ul><ul><ul><ul><li>Advisor (RCP) </li></ul></ul></ul><ul><ul><li>By default each part is placed in a separate Eclipse plug-in </li></ul></ul>
  40. 40. Java 5.0 Constructs <ul><li>For a new model, EMF 2.3 targets the compiler compliance level specified by the containing project (or the workspace default) </li></ul><ul><li>To generate code with Java 5.0 constructs for an existing model, use the “Compliance Level” property on the GenModel </li></ul>
  41. 41. Summary of Generated Artifacts <ul><li>Model </li></ul><ul><ul><li>Interfaces and classes </li></ul></ul><ul><ul><li>Type-safe enumerations </li></ul></ul><ul><ul><li>Package (metadata) </li></ul></ul><ul><ul><li>Factory </li></ul></ul><ul><ul><li>Switch utility </li></ul></ul><ul><ul><li>Adapter factory base </li></ul></ul><ul><ul><li>Validator </li></ul></ul><ul><ul><li>Custom resource </li></ul></ul><ul><ul><li>XML Processor </li></ul></ul><ul><li>Edit (UI independent) </li></ul><ul><ul><li>Item providers </li></ul></ul><ul><ul><li>Item provider adapter factory </li></ul></ul><ul><li>Editor </li></ul><ul><ul><li>Model Wizard </li></ul></ul><ul><ul><li>Editor </li></ul></ul><ul><ul><li>Action bar contributor </li></ul></ul><ul><ul><li>Advisor (RCP) </li></ul></ul><ul><li>Tests </li></ul><ul><ul><li>Test cases </li></ul></ul><ul><ul><li>Test suite </li></ul></ul><ul><ul><li>Stand-alone example </li></ul></ul><ul><li>Manifests, plug-in classes, properties, icons... </li></ul>
  42. 42. Regeneration and Merge <ul><li>Hand-written code can be added to generated code and preserved during regeneration </li></ul><ul><ul><li>This merge capability has an Eclipse dependency, so is not available standalone </li></ul></ul><ul><li>All generated classes, interfaces, methods and fields include @generated marker in their Javadoc </li></ul><ul><li>To replace generated code: </li></ul><ul><ul><li>Remove @generated marker </li></ul></ul><ul><ul><li>Or include additional text, e.g. </li></ul></ul><ul><ul><ul><li>@generated NOT </li></ul></ul></ul><ul><li>Methods without @generated marker are left alone during regeneration </li></ul>
  43. 43. Regeneration and Merge <ul><li>Extend (vs. replace) generated method through redirection </li></ul><ul><ul><li>Append “Gen” suffix to the generated method's name </li></ul></ul>/** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public String getName Gen () { return name; } public String getName () { return format(getNameGen()); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public String getName () { return name; }
  44. 44. The Code Generation Process Java Code Model Importer JET Simplified version UML Java Model ? XML Schema GenModel Ecore
  45. 45. The Code Generation Process Java Code Merged Java Code Model Importer JET JMerge Generated Java Code Full version UML Java Model ? XML Schema GenModel Ecore
  46. 46. Agenda <ul><li>EMF in a Nutshell </li></ul><ul><li>EMF Components </li></ul><ul><li>The Ecore Metamodel </li></ul><ul><li>Code Generation, Regeneration and Merge </li></ul><ul><li>The EMF Runtime </li></ul><ul><li>Recording Changes </li></ul><ul><li>Validation </li></ul><ul><li>Summary </li></ul>
  47. 47. EMF Runtime <ul><li>Persistence and serialization of model data </li></ul><ul><ul><li>Proxy resolution and demand load </li></ul></ul><ul><li>Automatic notification of model changes </li></ul><ul><li>Bi-directional reference handshaking </li></ul><ul><li>Dynamic object access through a reflective API </li></ul><ul><li>Runtime environments </li></ul><ul><ul><li>Eclipse </li></ul></ul><ul><ul><ul><li>Full IDE </li></ul></ul></ul><ul><ul><ul><li>RCP </li></ul></ul></ul><ul><ul><li>Standalone Java </li></ul></ul>
  48. 48. Persistence and Serialization <ul><li>Serialized data is referred to as a resource </li></ul><ul><li>Data can be spread out among a number of resources in a resource set </li></ul><ul><li>One resource is loaded at a time, even if it has references to objects in other resources in the resource set </li></ul><ul><ul><li>Proxies exist for objects in other resources </li></ul></ul><ul><ul><li>Lazy or demand loading of other resources as needed </li></ul></ul><ul><ul><li>A resource can be unloaded </li></ul></ul>
  49. 49. Resource Set <ul><li>Context for multiple resources that may have references among them </li></ul><ul><li>Usually just an instance of ResourceSetImpl, or a customized subclass </li></ul><ul><li>Provides factory method for creating new resources in the set: </li></ul><ul><li>Also provides access to the registries, URI converter, and default load options for the set </li></ul>ResourceSet rs = new ResourceSetImpl (); URI uri = URI.createFileURI(&quot;C:/data/po.xml&quot;); Resource resource = rs. createResource (uri);
  50. 50. Resource Factory Registry <ul><li>Returns a resource factory for a given type of resource </li></ul><ul><ul><li>Based on the URI scheme or filename extension </li></ul></ul><ul><ul><li>Determines the type of resource, hence format for save/load </li></ul></ul><ul><li>For models created from XML Schema, the generated custom resource factory implementation should be registered to ensure schema-conformant serialization </li></ul><ul><ul><li>When running as a plug-in under Eclipse, EMF provides an extension point for registering resource factories </li></ul></ul><ul><ul><li>Generated plugin.xml registers generated resource factory against a package specific extension (e.g. “po”) </li></ul></ul><ul><li>Global registry: Resource.Factory.Registry.INSTANCE </li></ul><ul><ul><li>Consulted if no registered resource factory found locally </li></ul></ul>Resource.Factory.Registry reg = rs. getResourceFactoryRegistry (); reg. getExtensionToFactoryMap ().put(&quot; xml &quot;, new XMLResourceFactoryImpl ());
  51. 51. Package Registry <ul><li>Returns the package identified by a given namespace URI </li></ul><ul><ul><li>Used during loading to access the factory for creating instances </li></ul></ul><ul><li>Global registry: EPackage.Registry.INSTANCE </li></ul><ul><ul><li>Consulted if no registered package found locally </li></ul></ul><ul><li>Running in Eclipse, EMF provides an extension point for globally registering generated packages </li></ul><ul><li>Even standalone, a package automatically registers itself when accessed: </li></ul>EPackage.Registry registry = rs. getPackageRegistry (); registry.put( POPackage.eNS_URI , POPackage.eINSTANCE ); POPackage poPackage = POPackage.eINSTANCE;
  52. 52. Resource <ul><li>Container for objects that are to be persisted together </li></ul><ul><ul><li>Convert to and from persistent form via save() and load() </li></ul></ul><ul><ul><li>Access contents of resource via getContents() </li></ul></ul><ul><li>EMF provides XMLResource implementation </li></ul><ul><li>Other, customized XML resource implementations, provided, too (e.g. XMI, Ecore, EMOF) </li></ul>URI uri = URI.createFileURI(&quot;C:/data/po.xml&quot;); Resource resource = rs.createResource(uri); resource. getContents ().add(p1); resource. save (null); <PurchaseOrder> <shipTo>John Doe</shipTo> <next>p2.xml#p2</next> </PurchaseOrder>
  53. 53. Proxy Resolution and Demand Load PurchaseOrder p2 = p1. getNext (); p1 p1.xml next p2 p2.xml proxyURI=“ p2.xml #p2” next proxyURI=“p2.xml#p2” next <PurchaseOrder> <shipTo>John Doe</shipTo> <next> p2.xml#p2 </next> </PurchaseOrder> p1.xml
  54. 54. Model Change Notification <ul><li>Every EMF object is also a Notifier </li></ul><ul><ul><li>Send notification whenever an attribute or reference is changed </li></ul></ul><ul><ul><li>EMF objects can be “observed” in order to update views and dependent objects </li></ul></ul>Adapter poObserver = ... purchaseOrder. eAdapters ().add(poObserver);
  55. 55. Model Change Notification <ul><li>Observers or listeners in EMF are called adapters </li></ul><ul><ul><li>An adapter can also extend class behavior without subclassing </li></ul></ul><ul><ul><li>For this reason they are typically added using an AdapterFactory </li></ul></ul>PurchaseOrder purchaseOrder = ... AdapterFactory somePOAdapterFactory = ... Object poExtensionType = ... if (somePOAdapterFactory. isFactoryForType (poExtensiontype)) { Adapter poAdapter = somePOAdapterFactory. adapt (purchaseOrder, poExtensionType); ... }
  56. 56. Model Change Notification <ul><li>Efficient notification in “set” methods </li></ul><ul><ul><li>Checks for listeners before creating and sending notification </li></ul></ul>public String getShipTo() { return shipTo; } public void setShipTo(String newShipTo) { String oldShipTo = shipTo; shipTo = newShipTo; if (eNotificationRequired()) eNotify(new ENotificationImpl(this, ... ); }
  57. 57. Bidirectional Reference Handshaking public interface PurchaseOrder { PurchaseOrder getNext (); void setNext (PurchaseOrder value); PurchaseOrder getPrevious (); void setPrevious (PurchaseOrder value); } Invariant imposed by the bidirectional reference: po.getNext().getPrevious() == po
  58. 58. Bidirectional Reference Handshaking p1. setNext (p3); p2 p1 p2 p3 previous next next previous next previous next previous change notification
  59. 59. Bidirectional Reference Handshaking <ul><li>This multi-step procedure is implemented using InternalEObject methods: </li></ul><ul><ul><li>eInverseRemove() </li></ul></ul><ul><ul><li>eInverseAdd() </li></ul></ul><ul><li>Framework list implementations and generated setters directly invoke them on target objects as needed </li></ul><ul><li>Notifications are accumulated using a NotificationChain and fired off at the end </li></ul><ul><ul><li>They are not used to implement the handshaking </li></ul></ul>
  60. 60. Reflection <ul><li>All EMF classes implement interface EObject </li></ul><ul><li>Provides an efficient API for manipulating objects reflectively </li></ul><ul><ul><li>Used by the framework (e.g., serialization/deserialization, copy utility, generic editing commands, etc.) </li></ul></ul><ul><ul><li>Also key to integrating tools and applications built using EMF </li></ul></ul>public interface EObject { EClass eClass (); Object eGet (EStructuralFeature sf); void eSet (EStructuralFeature sf, Object val); ... }
  61. 61. Reflection Example <ul><li>Setting an attribute using generated API: </li></ul><ul><li>Using reflective API: </li></ul>PurchaseOrder po = ... po. setBillTo (&quot;123 Elm St.&quot;); EObject po = ... EClass poClass = po.eClass(); po. eSet (poClass.getEStructuralFeature(&quot;billTo&quot;), &quot;123 Elm St.&quot;);
  62. 62. Reflective Performance <ul><li>Efficient generated switch-based implementation of reflective methods </li></ul>public Object eGet (int featureID, ...) { switch (featureID) { case POPackage.PURCHASE_ORDER__SHIP_TO: return getShipTo (); case POPackage.PURCHASE_ORDER__BILL_TO: return getBillTo (); ... } }
  63. 63. Reflection Benefits <ul><li>Reflection allows generic access to any EMF model </li></ul><ul><ul><li>Similar to Java’s introspection capability </li></ul></ul><ul><ul><li>Every EObject (that is, every EMF object) implements the reflection API </li></ul></ul><ul><li>An integrator need only know your model! </li></ul><ul><li>A generic EMF model editor uses the reflection API </li></ul><ul><ul><li>Can be used to edit any EMF model </li></ul></ul>
  64. 64. Dynamic EMF <ul><li>Ecore models can be defined dynamically in memory </li></ul><ul><ul><li>No generated code required </li></ul></ul><ul><ul><li>Dynamic implementation of reflective EObject API provides same runtime behavior as generated code </li></ul></ul><ul><ul><li>Also supports dynamic subclasses of generated classes </li></ul></ul><ul><li>All EMF model instances, whether generated or dynamic, are treated the same by the framework </li></ul><ul><li>A dynamic Ecore model can be defined by </li></ul><ul><ul><li>Instantiating model elements with the Ecore API </li></ul></ul><ul><ul><li>Loading from a .ecore file </li></ul></ul>
  65. 65. Dynamic EMF Example <ul><li>Model definition using the Ecore API </li></ul>EPackage poPackage = EcoreFactory.eINSTANCE. createEPackage (); poPackage. setName (&quot;po&quot;); poPackage. setNsURI (&quot;;);    EClass poClass = EcoreFactory.eINSTANCE. createEClass (); poClass. setName (&quot;PurchaseOrder&quot;); poPackage. getEClassifiers ().add(poClass);   EAttribute billTo = EcoreFactory.eINSTANCE. createEAttribute (); billTo. setName (&quot;billTo&quot;); billTo. setEType (EcorePackage.eINSTANCE. getEString ()); poClass. getEStructuralFeatures ().add(billTo); ... EObject po = EcoreUtil.create(poClass); po.eSet(billTo,&quot;123 Elm St.&quot;);
  66. 66. XML Processor <ul><li>Simplified API for loading and saving XML </li></ul><ul><ul><li>Handles resource set, registries, etc. under the covers </li></ul></ul><ul><li>Can automatically create a dynamic Ecore representation of a schema </li></ul><ul><ul><li>Load/save instance documents without generating code </li></ul></ul><ul><ul><li>Manipulate the objects using reflective EObject API </li></ul></ul>URI schemaURI = ... String instanceFileName = ... XMLProcessor processor = new XMLProcessor (schemaURI); Resource resource = processor. load (instanceFileName, null); EObject documentRoot = resource.getContents.get(0);
  67. 67. Agenda <ul><li>EMF in a Nutshell </li></ul><ul><li>EMF Components </li></ul><ul><li>The Ecore Metamodel </li></ul><ul><li>Code Generation, Regeneration and Merge </li></ul><ul><li>The EMF Runtime </li></ul><ul><li>Recording Changes </li></ul><ul><li>Validation </li></ul><ul><li>Summary </li></ul>
  68. 68. Recording Changes <ul><li>EMF provides facilities for recording the changes made to instances of an Ecore model </li></ul><ul><li>Change Model </li></ul><ul><ul><li>An EMF model for representing changes to objects </li></ul></ul><ul><ul><li>Directly references affected objects </li></ul></ul><ul><ul><li>Includes “apply changes” capability </li></ul></ul><ul><li>Change Recorder </li></ul><ul><ul><li>EMF adapter </li></ul></ul><ul><ul><li>Monitors objects to produce a change description (an instance of the change model) </li></ul></ul>
  69. 69. Change Model
  70. 70. Change Recorder <ul><li>Can be attached to EObjects, Resources, and ResourceSets </li></ul><ul><ul><li>Monitors changes to the objects and their contents trees </li></ul></ul><ul><li>Produces a description of the changes needed to return to the original state (a reverse delta) </li></ul><ul><li>Result: a change description with one change, setting billTo to “123 Elm St.” </li></ul>PurchaseOrder order = ... order.setBillTo(&quot;123 Elm St.&quot;); ChangeRecorder recorder = new ChangeRecorder(); recorder. beginRecording (Collections.singleton(order)); order.setBillTo(&quot;456 Cherry St.&quot;); ChangeDescription change = recorder. endRecording ();
  71. 71. Applying Changes <ul><li>Given a change description, the change can be applied: </li></ul><ul><ul><li>ChangeDescription.apply() </li></ul></ul><ul><ul><ul><li>consumes the changes, leaving the description empty </li></ul></ul></ul><ul><ul><li>ChangeDescription.applyAndReverse() </li></ul></ul><ul><ul><ul><li>reverses the changes, leaving a description of the changes originally made (the forward delta) </li></ul></ul></ul><ul><li>The model is always left in an appropriate state for applying the resulting change description </li></ul>
  72. 72. Example: Transaction Capability <ul><li>If any part of the transaction fails, undo the changes </li></ul>ChangeRecorder changeRecorder = new ChangeRecorder(resourceSet); try { // modifications within resource set } catch (Exception e) { changeRecorder. endRecording (). apply (); }
  73. 73. Agenda <ul><li>EMF in a Nutshell </li></ul><ul><li>EMF Components </li></ul><ul><li>The Ecore Metamodel </li></ul><ul><li>Code Generation, Regeneration and Merge </li></ul><ul><li>The EMF Runtime </li></ul><ul><li>Recording Changes </li></ul><ul><li>Validation </li></ul><ul><li>Summary </li></ul>
  74. 74. Validation Framework <ul><li>Model objects validated by external EValidator </li></ul><ul><li>Detailed results accumulated as Diagnostics </li></ul><ul><ul><li>Essentially a non-Eclipse equivalent to IStatus </li></ul></ul><ul><ul><li>Records severity, source plug-in ID, status code, message, other arbitrary data, and nested children </li></ul></ul>public interface Evalidator { boolean validate (EObject eObject, DiagnosticChain diagnostics, Map Context); boolean validate (EClass eClass, EOjbect eObject, DiagnosticChain, diagnostics, Map context); boolean validate (EDataType eDataType, Object value, DiagnosticChain diagnostics, Map context); ... }
  75. 75. Invariants and Constraints <ul><li>Invariant </li></ul><ul><ul><li>Defined directly on the class, as an operation with <<inv>> stereotype </li></ul></ul><ul><ul><li>Stronger statement about validity than a constraint </li></ul></ul><ul><li>Constraint </li></ul><ul><ul><li>Externally defined for the class via a method on the validator </li></ul></ul>
  76. 76. Generated EValidator Implementations <ul><li>Generated for each package that defines invariants or constraints </li></ul><ul><li>Dispatches validation to type-specific methods </li></ul><ul><li>For classes, a validate method is called for each invariant and constraint </li></ul><ul><ul><li>Method body must be hand coded for invariants and named constraints </li></ul></ul>
  77. 77. Schema-Based Constraints <ul><li>In XML Schema, named constraints are defined via annotations: </li></ul><ul><li>Also, constraints can be defined as facets on simple types, and no additional coding is required </li></ul><ul><ul><li>Constraint method implementation generated </li></ul></ul><xsd:annotation> <xsd:appinfo source=&quot;; ecore:key=&quot;constraints&quot;>VolumeDiscount</xsd:appinfo> </xsd:annotation> <xsd:simpleType name=&quot;SKU&quot;> <xsd:restriction base=&quot;xsd:string&quot;> <xsd:pattern value=&quot;d{3}-[A-Z]{2}&quot;/> </xsd:restriction> </xsd:simpleType>
  78. 78. Framework EValidator Implementations <ul><li>EObjectValidator validates basic EObject constraints: </li></ul><ul><ul><li>Multiplicities are respected </li></ul></ul><ul><ul><li>Proxies resolve </li></ul></ul><ul><ul><li>All referenced objects are contained in a resource </li></ul></ul><ul><ul><li>Data type values are valid </li></ul></ul><ul><li>Used as base of generated validators and directly for packages without additional constraints defined </li></ul>
  79. 79. Framework EValidator Implementations <ul><li>Diagnostician walks a containment tree of model objects, dispatching to package-specific validators </li></ul><ul><ul><li>Diagnostician.validate() is the usual entry point </li></ul></ul><ul><ul><li>Obtains validators from its EValidator.Registry </li></ul></ul>Diagnostician validator = Diagnostician.INSTANCE ; Diagnostic diagnostic = validator. validate (order); if (diagnostic.getSeverity() == Diagnostic.ERROR) { // handle error } for (Diagnostic child : diagnostic.getChildren()) { // handle child diagnostic }
  80. 80. Agenda <ul><li>EMF in a Nutshell </li></ul><ul><li>EMF Components </li></ul><ul><li>The Ecore Metamodel </li></ul><ul><li>Code Generation, Regeneration and Merge </li></ul><ul><li>The EMF Runtime </li></ul><ul><li>Recording Changes </li></ul><ul><li>Validation </li></ul><ul><li>Summary </li></ul>
  81. 81. Summary <ul><li>EMF is low-cost modeling for the Java mainstream </li></ul><ul><li>Boosts productivity and facilitates integration </li></ul><ul><li>Mixes modeling with programming to maximize the effectiveness of both </li></ul>
  82. 82. Summary <ul><li>EMF provides… </li></ul><ul><ul><li>A metamodel (Ecore) with which your domain model can be specified </li></ul></ul><ul><ul><ul><li>Your model can be created from UML, XML Schema or annotated Java interfaces </li></ul></ul></ul><ul><ul><li>Generated Java code </li></ul></ul><ul><ul><ul><li>Efficient and straightforward </li></ul></ul></ul><ul><ul><ul><li>Code customization preserved </li></ul></ul></ul><ul><ul><li>Persistence and Serialization </li></ul></ul><ul><ul><ul><li>Resource-based serialization </li></ul></ul></ul><ul><ul><ul><li>Proxy resolution and demand loading </li></ul></ul></ul><ul><ul><ul><li>Default resource implementation is XMI (XML metadata interchange), but can be overridden </li></ul></ul></ul>
  83. 83. Summary <ul><li>EMF provides… </li></ul><ul><ul><li>Model change notification is built in </li></ul></ul><ul><ul><ul><li>Just add adapters (observers) where needed </li></ul></ul></ul><ul><ul><li>Reflection and dynamic EMF </li></ul></ul><ul><ul><ul><li>Full introspection capability </li></ul></ul></ul><ul><ul><li>Simple change recording and roll-back </li></ul></ul><ul><ul><li>Extensible validation framework </li></ul></ul><ul><ul><li>Standalone runtime support </li></ul></ul><ul><ul><li>A UI-independent layer for viewing and editing modeled data (EMF.Edit) </li></ul></ul>
  84. 84. Part 2: Advanced Features of the Eclipse Modeling Framework
  85. 85. Agenda <ul><li>Working with Resources and ResourceSets </li></ul><ul><li>Customizing the Code Generator </li></ul><ul><li>Tuning for Performance and/or Memory Footprint </li></ul><ul><li>Importers and Exporters </li></ul><ul><li>Supporting Backward and Forward Compatibility </li></ul><ul><li>Summary </li></ul>
  86. 86. Working with Resources and ResourceSets <ul><li>Working with proxies </li></ul><ul><ul><li>Identifying proxies </li></ul></ul><ul><ul><li>Using the Validation Framework to detect unresolved proxies </li></ul></ul><ul><ul><li>Using “fragment queries” to handle unresolved proxies </li></ul></ul><ul><li>Cross-Resource Containment </li></ul><ul><li>Inverse References </li></ul><ul><li>Resource Tips & Tricks </li></ul><ul><ul><li>Unloading </li></ul></ul><ul><ul><li>Tracking modification </li></ul></ul><ul><ul><li>Am I loading something? </li></ul></ul>
  87. 87. Persistence and Serialization Review <ul><li>Serialized data is referred to as a resource </li></ul><ul><li>Data can be spread out among a number of resources in a resource set </li></ul><ul><li>One resource is loaded at a time, even if it has references to objects in other resources in the resource set </li></ul><ul><ul><li>Proxies exist for objects in other resources </li></ul></ul><ul><ul><li>Lazy or demand loading of other resources as needed </li></ul></ul><ul><ul><li>A resource can be unloaded </li></ul></ul>
  88. 88. Identifying Proxies <ul><li>In some scenarios it may be important to know up-front what are the proxies referenced by a given object </li></ul><ul><ul><li>Check whether the user has everything that will be necessary to load the model </li></ul></ul><ul><ul><li>Extract missing resources from the repository </li></ul></ul><ul><ul><li>Decide whether loading a specific object is a long or short operation </li></ul></ul><ul><li>org.eclipse.emf.ecore.util.EcoreUtil.ProxyCrossReferencer </li></ul><ul><ul><li>A CrossReferencer that finds proxies without resolving them </li></ul></ul><ul><ul><li>For each object in a given context (resource, resource set, EObject, collection), checks if the referenced objects are in the same resource or not </li></ul></ul>
  89. 89. Going Deeper: EcoreUtil’s CrossReferencers <ul><li>Utility classes that find “uses” of an object </li></ul><ul><li>Also the data structures that hold the objects they find </li></ul><ul><ul><li>A CrossReferecer is a java.util.Map </li></ul></ul><ul><ul><li>On each Map.Entry </li></ul></ul><ul><ul><ul><li>Key: reference target </li></ul></ul></ul><ul><ul><ul><li>Value: list of EStructuralFeature.Setting with all the source object-feature pairs referencing the keyed target </li></ul></ul></ul>
  90. 90. Going Deeper: EStructuralFeature.Setting <ul><li>Interface that represents the value held by a feature of an EObject </li></ul><ul><li>Exposes all the feature-related methods of EObject </li></ul><ul><ul><li>eGet, eSet, eIsSet, and eUnset </li></ul></ul>
  91. 91. Going Deeper: Types of Reference <ul><li>Containment Reference </li></ul><ul><ul><li>Has an “implicit” opposite (eObject.eContainer()) </li></ul></ul><ul><li>Container Reference </li></ul><ul><ul><li>An explicit reference defined as the opposite of a containment reference </li></ul></ul><ul><li>Cross-Reference </li></ul><ul><ul><li>May or may not have an opposite </li></ul></ul><ul><li>Any reference can refer to an EObject located in either the same or different resource </li></ul>
  92. 92. EcoreUtil.ProxyCrossReferencer public static void printProxiesDetails(ResourceSet resourceSet ) { int counter = 0; Map<EObject, Collection<EStructuralFeature.Setting>> map = ProxyCrossReferencer .find(resourceSet); for (Map.Entry<EObject, Collection<EStructuralFeature.Setting>> entry : map.entrySet()) { EObject proxyEObject = entry. getKey (); System.out.println (&quot;&quot; + ++counter + &quot;. &quot; + EcoreUtil.getURI(proxyEObject)); System.out.println (&quot;Is Proxy: &quot; + proxyEObject.eIsProxy()); for (EStructuralFeature.Setting setting : entry. getValue ()) { System.out.println (&quot; Feature: &quot; + setting. getEStructuralFeature ().getName()); EObject eObject = setting. getEObject (); EStructuralFeature nameFeature = eObject.eClass().getEStructuralFeature(&quot;name&quot;); if (nameFeature != null) { System.out.println (&quot; EObject.getName(): &quot; + eObject.eGet(nameFeature)); } } } } 1. uri3.xmi#/0 Is Proxy: true Feature: home EObject.getName(): john
  93. 93. Validating Proxies <ul><li>The validation framework can be used to validate proxies </li></ul><ul><li>The EObjectValidator checks if all the referenced objects of a given EObject are resolved </li></ul><ul><ul><li>The proxy references are resolved during the validation </li></ul></ul><ul><li>If a proxy is broken, the validation produces a Diagnostic with EObjectValidator. EOBJECT__EVERY_PROXY_RESOLVES as its error code </li></ul>
  94. 94. Validating Proxies public static void validateProxies(EObject eObject) { Diagnostic diagnostic = Diagnostician .INSTANCE. validate (eObject); if (diagnostic.getSeverity() == Diagnostic.ERROR) { if ( hasEveryProxyResolvesCode (diagnostic)) { System.out.println (&quot;Broken proxies found!&quot;); return; } } System.out.println (&quot;Proxies are fine.&quot;); } public static boolean hasEveryProxyResolvesCode (Diagnostic diagnostic) { if (diagnostic. getCode () == EObjectValidator. EOBJECT__EVERY_PROXY_RESOLVES ) return true; for (Diagnostic childDiagnostic : diagnostic.getChildren()) { return hasEveryProxyResolvesCode (childDiagnostic); } return false; }
  95. 95. Handling Broken Proxies <ul><li>Your application can provide a mechanism to handle broken proxies by </li></ul><ul><ul><li>Reporting the error to the user </li></ul></ul><ul><ul><li>Avoiding use of the object(s) that could not be resolved </li></ul></ul><ul><ul><li>Recovering the missing object(s) </li></ul></ul><ul><li>EMF doesn’t provide such a mechanism but provides hooks to help you implement one </li></ul><ul><ul><li>Fragment query capability is one of these hooks </li></ul></ul>
  96. 96. Stepping Back: Uniform Resource Identifier (URI) <ul><li>A formatted string that serves as an identifier for a resource </li></ul><ul><li>Specification: </li></ul><ul><ul><li>Definition: </li></ul></ul><ul><ul><li>Generic Syntax: </li></ul></ul><ul><li>Syntax: </li></ul><ul><ul><li>Generic </li></ul></ul><ul><ul><li>[ scheme : ] scheme-specific-part [ # fragment ] </li></ul></ul><ul><ul><li>Hierarchical </li></ul></ul><ul><ul><ul><li>[ scheme : ][ // authority ][ path ][ ? query ][ # fragment ] </li></ul></ul></ul><ul><li>Used in EMF to identify a resource, an object in a resource, or an Ecore package (namespace URI) </li></ul>
  97. 97. Fragment Queries <ul><li>The idea is to “decorate” the fragment portion of a URI with details that further describe the referenced object </li></ul><ul><ul><li>The description can be used by a service to locate the object or to enrich an error message to be presented to the user </li></ul></ul><ul><li>Query data </li></ul><ul><ul><li>Added to the fragment portion of the object’s URI </li></ul></ul><ul><ul><li>Must be at the end of the URI fragment portion </li></ul></ul><ul><ul><li>Is delimited by “?” </li></ul></ul><ul><ul><li>Example: file:/c:/dir/library.xmi #//@books.0?Book.ISBN.0131425420? </li></ul></ul>Fragment Query URI Fragment
  98. 98. Saving Fragment Queries <ul><li>If you are using a XMLResource to serialize your objects </li></ul><ul><ul><li>Override the getURIFragmentQuery(Resource, EObject) method of org.eclipse.emf.ecore.xmi.impl.XMLHelperImpl to return the query that should be serialized for the given EObject </li></ul></ul><ul><ul><li>Override the createXMLHelper() method of org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl to return an instance of your XMLHelper </li></ul></ul><ul><li>The getURIFragmentQuery(…) method returns the string that is used as the “query” </li></ul><ul><ul><li>The string should not contain the delimiter character ( ? ) </li></ul></ul><ul><ul><li>A null string indicates that there is no query </li></ul></ul><ul><ul><li>The characters must be valid URI fragment characters (as defined by the specification) </li></ul></ul>
  99. 99. Going Deeper: org.eclipse.emf.ecore.xmi.XMLHelper <ul><li>Interface used by the default resource implementations </li></ul><ul><ul><li>Not used by clients </li></ul></ul><ul><li>Single place where the methods used to save and load objects are located </li></ul><ul><ul><li>Simplifies customizations </li></ul></ul>
  100. 100. Using Fragment Queries <ul><li>EMF doesn’t enforce the use of fragment queries </li></ul><ul><li>Reasonable approach: </li></ul><ul><ul><li>Load an object </li></ul></ul><ul><ul><li>Try to resolve its proxies </li></ul></ul><ul><ul><li>Identify the remaining (broken) proxies </li></ul></ul><ul><ul><li>Use the fragment query of the broken proxies to either report the problem to the user or recover the missing objects </li></ul></ul>
  101. 101. Cross-Resource Containment <ul><li>Allows an object hierarchy to be persisted across multiple resources </li></ul><ul><ul><li>eObject.eResource() may be different from eObject.eContainer().eResource() </li></ul></ul><ul><li>Must be explicitly enabled </li></ul><ul><ul><li>The containment reference has to be set to resolve proxies </li></ul></ul><ul><ul><li>Also, on generated models, the value of the “Containment Proxies” generator model property has to be set to ‘true’ </li></ul></ul>
  102. 102. Enabling Cross-Resource Containment EReference houses = EcoreFactory.eINSTANCE.createEReference(); houses.setName(&quot;houses&quot;); houses.setEType(house); houses.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY); houses.setContainment(true); houses. setResolveProxies ( true ); person.getEStructuralFeatures().add(houses); Dynamic Model Generated Model
  103. 103. Cross-Resource Containment { Library library = LibFactory.eINSTANCE.createLibrary(); Book book = LibFactory.eINSTANCE.createBook(); library .getBooks().add(book); System.out.println (library.eResource() + &quot; - &quot; + book.eResource()); Resource libraryResource = new ResourceImpl(URI.createURI(&quot; lib &quot;)); libraryResource .getContents().add( library ); System.out.println (library.eResource().getURI() + &quot; - “ + book.eResource().getURI()); Resource bookResource = new ResourceImpl(URI.createURI(&quot; book &quot;)); bookResource .getContents().add( book ); System.out.println (library.eResource().getURI() + &quot; - &quot; + book.eResource().getURI()); bookResource .getContents().remove( book ); System.out.println (library.eResource().getURI() + &quot; - &quot; + book.eResource().getURI()); } null - null lib - lib lib - book lib - lib
  104. 104. EcoreUtil Methods for Cross-Resource Containment <ul><li>When the containment tree is spread across multiple files, one may be interested in differentiating the “local” children of an object from children in other resources </li></ul><ul><li>The *Proper* methods available in EcoreUtil only deal with the “local” children of a containment tree </li></ul>All children Local children
  105. 105. Inverse References <ul><li>Sometimes it may be handy to retrieve the opposite of a unidirectional association end </li></ul><ul><ul><li>For example, the use case you are implementing requires a navigation that was not anticipated when the model was defined </li></ul></ul><ul><li>EMF provides two mechanisms </li></ul><ul><ul><li>CrossReferencer </li></ul></ul><ul><ul><li>ECrossReferenceAdapter </li></ul></ul>
  106. 106. Going Deeper: Associations and References <ul><li>An association between two classes allows their instances to “communicate” with each other </li></ul><ul><li>Each navigable end of an association is represented by an EReference in Ecore </li></ul><ul><ul><li>If the association is bidirectional, it will be represented by two references, r1 and r2 where r1.getEOpposite() == r2 && r2.getEOpposite() == r1 </li></ul></ul>Associations References
  107. 107. Using a CrossReferencer <ul><li>Dynamically computes a map with the target object and the list of settings that “refer” to it </li></ul><ul><ul><li>This computation may be a long operation depending on the number of objects </li></ul></ul><ul><li>The map represents a snapshot of the state of the objects </li></ul><ul><ul><li>As the objects change, the settings’ values may become inconsistent with the map </li></ul></ul><ul><li>Requires a context to compute the map </li></ul><ul><ul><li>The context can be a collection of EObjects, a resource, or a resource set, or a combination of these </li></ul></ul><ul><ul><li>Objects that are not in the scope of the context won’t be available in the map </li></ul></ul>
  108. 108. Using a CrossReferencer { Library library = LibFactory.eINSTANCE.createLibrary(); Book book = LibFactory.eINSTANCE.createBook(); book.setTitle(&quot;EMF&quot;); Person dave = LibFactory.eINSTANCE.createPerson(); library .getBooks().add( book ); library .getWriters().add( dave ); book .getWriters().add( dave ); Map<EObject, Collection<EStructuralFeature.Setting>> map = EcoreUtil.CrossReferencer .find(Collections.singleton( library )); Collection<EStructuralFeature.Setting> settings = map.get(dave); if (settings != null) { for (EStructuralFeature.Setting setting : settings) { if (setting. getEObject () == book && setting. getEStructuralFeature () == LibPackage.Literals. BOOK__WRITERS ) { System.out.println (&quot;Found it. The book is &quot;&quot; + book.getTitle() + &quot;&quot;&quot;); } } } } Found it. The book is &quot;EMF&quot;
  109. 109. Using the ECrossReferenceAdapter <ul><li>A special adapter that </li></ul><ul><ul><li>Attaches itself to all objects in a containment hierarchy </li></ul></ul><ul><ul><ul><li>May pose a memory footprint problem depending on the number of objects </li></ul></ul></ul><ul><ul><li>Keeps a CrossReferencer in sync with the state of the objects </li></ul></ul><ul><li>The application can determine and change the context used when computing the map </li></ul>
  110. 110. Using the ECrossReferenceAdapter { Library library = LibFactory.eINSTANCE.createLibrary(); ECrossReferenceAdapter adapter = new ECrossReferenceAdapter (); library.eAdapters().add( adapter ); Book book = LibFactory.eINSTANCE.createBook(); book.setTitle(&quot;EMF&quot;); Person dave = LibFactory.eINSTANCE.createPerson(); library .getBooks().add( book ); library .getWriters().add( dave ); book .getWriters().add( dave ); Collection<EStructuralFeature.Setting> settings = adapter. getNonNavigableInverseReferences (dave); for (EStructuralFeature.Setting setting : settings) { if (setting. getEObject () == book && setting. getEStructuralFeature () == LibPackage.Literals. BOOK__WRITERS ) { System.out.println (&quot;Found it. The book is &quot;&quot; + book.getTitle() + &quot;&quot;&quot;); } } } Found it. The book is &quot;EMF&quot;
  111. 111. Resource Tips & Tricks <ul><li>Unloading a resource </li></ul><ul><ul><li>Resource.unload() </li></ul></ul><ul><ul><li>EMF’s default implementation performs the following steps: </li></ul></ul><ul><ul><ul><li>Sets the loaded attribute to false; </li></ul></ul></ul><ul><ul><ul><li>Caches an iterator with all the proper contents of all objects held by the resource </li></ul></ul></ul><ul><ul><ul><li>Clears the resource’s content, error and warning lists </li></ul></ul></ul><ul><ul><ul><li>Turns each object returned by the iterator into a proxy and clears its adapter list </li></ul></ul></ul><ul><ul><ul><li>Fires a notification </li></ul></ul></ul><ul><ul><ul><ul><li>Feature ID = Resource. RESOURCE__IS_LOADED </li></ul></ul></ul></ul><ul><ul><li>You may also remove the resource from the resource set </li></ul></ul>
  112. 112. Resource Tips & Tricks <ul><li>Tracking modification </li></ul><ul><ul><li>Resource.setTrackingModification(boolean) </li></ul></ul><ul><ul><li>When activated, EMF’s default implementation performs the following steps: </li></ul></ul><ul><ul><ul><li>Instantiates an Adapter and registers it on all proper objects </li></ul></ul></ul><ul><ul><ul><ul><li>The adapter calls Resource.setModified(boolean) after receiving a notification </li></ul></ul></ul></ul><ul><ul><ul><li>Registers the adapter on any object added to the resource and deregisters it from objects that are removed </li></ul></ul></ul><ul><ul><li>When deactivated, the default implementation removes the adapter from the objects </li></ul></ul><ul><ul><li>You can manually define what is the isModified state of a resource </li></ul></ul>
  113. 113. Resource Tips & Tricks <ul><li>Am I loading something? </li></ul><ul><ul><li>Resource.Internal.isLoading() </li></ul></ul><ul><ul><ul><li>Every Resource is supposed to implement the Resource.Internal interface </li></ul></ul></ul><ul><ul><li>When a resource is being loaded the isLoading() method returns true </li></ul></ul>
  114. 114. Agenda <ul><li>Working with Resources and ResourceSets </li></ul><ul><li>Customizing the Code Generator </li></ul><ul><li>Tuning for Performance and/or Memory Footprint </li></ul><ul><li>Importers and Exporters </li></ul><ul><li>Supporting Backward and Forward Compatibility </li></ul><ul><li>Summary </li></ul>
  115. 115. Generating Customized Code <ul><li>The EMF code generator can be customized in various ways to meet the needs of your application </li></ul><ul><li>There are different levels of customization </li></ul><ul><ul><li>Generator Options </li></ul></ul><ul><ul><li>Dynamic Templates </li></ul></ul><ul><ul><li>Generator Extension </li></ul></ul>
  116. 116. Generator Options <ul><li>The EMF code generator provides a number of options which can have a significant effect on the kind of code that is generated from the default templates </li></ul><ul><ul><li>Suppress Interfaces </li></ul></ul><ul><ul><li>Suppress EMF Metadata </li></ul></ul><ul><ul><li>Root Extends Interface </li></ul></ul><ul><ul><li>Suppress EMF Types </li></ul></ul><ul><ul><li>Suppress EMF Model Tags </li></ul></ul>
  117. 117. Generator Options <ul><li>All can be adjusted as properties of the GenModel element, the root object in the generator </li></ul>
  118. 118. Suppress Interfaces /** * A representation of the model object * 'Library'. * @model * @generated */ public interface Library extends EObject { /** * Returns the value of the ‘Name' attribute. * @model * @generated */ String getName(); ... } /** * A representation of the model object * 'Library'. * @model * @generated */ public class Library extends EObjectImpl implements EObject { /** * The default value of the 'Name' attribute. * @model * @generated */ protected static final NAME_EDEFAULT = null; ... }
  119. 119. Suppress Interfaces <ul><li>Improves performance since dispatch through an interface is slower and less likely to be in-lined by a JIT compiler </li></ul><ul><li>Reduces byte code footprint somewhat </li></ul><ul><li>Can only be used for models with no multiple inheritance </li></ul>
  120. 120. Suppress EMF Metadata <ul><li>Helps produce an API with no visible EMF dependencies, i.e. a &quot;pure&quot; API </li></ul>/** * The Package for the model. * @model kind=&quot;package&quot; * @generated */ public interface LibraryPackage extends EPackage { /** * The package name. * @generated */ String eNAME = &quot;library&quot;; ... /** * The meta object id for the 'Book' class. * @generated */ int BOOK = 0; ... } /** * The Package for the model. * @model kind=&quot;package&quot; * @generated */ public class LibraryPackageImpl extends EPackageImpl { /** * The package name. * @generated */ String eNAME = &quot;library&quot;; ... }
  121. 121. Root Extends Interface <ul><li>Helps produce an API with no visible dependencies on EMF, or an API that visibly participates in another framework </li></ul><ul><li>‘ Root Extends Class’ and ‘Root Implements Interface’ are also available (classes must implement InternalEObject) </li></ul>/** * A representation of the model object * 'Library'. * @model * @generated */ public interface Library { ... } /** * A representation of the model object * 'Library'. * @model * @generated */ public interface Library extends EObject { ... }
  122. 122. Suppress EMF Model Tags <ul><li>Helps produce an API with no visible dependencies on EMF </li></ul>/** * A representation of the model object * 'Library'. * @generated */ public interface Library extends EObject { ... /** * Returns the value of the Writers containment * reference list. * @generated */ EList<Writer> getWriters(); ... } /** * A representation of the model object * 'Library'. * @model * @generated */ public interface Library extends EObject { ... /** * Returns the value of the Writers containment * reference list. * @model containment=&quot;true&quot; * type=&quot;org.eclipse.example.library.Writer&quot; * @generated */ EList<Writer> getWriters(); ... }
  123. 123. Suppress EMF Types <ul><li>EList, EMap, and EObject suppressed </li></ul><ul><li>Applies to feature, operation and parameter types </li></ul><ul><li>Helps produce an API with no visible dependencies on EMF </li></ul>/** * Returns the value of the Writers containment * reference list. * @model containment=&quot;true“ * type=&quot;org.eclipse.exasmple.library.Writer&quot; * @generated */ List <Writer> getWriters(); /** * Returns the value of the Writers containment * reference list. * @model containment=&quot;true&quot; * type=&quot;org.eclipse.example.library.Writer&quot; * @generated */ EList <Writer> getWriters();
  124. 124. Dynamic Templates <ul><li>The content of the templates used by the EMF code generator can be changed or replaced by enabling dynamic templates </li></ul><ul><li>Set the value of the ‘Dynamic Templates’ generator model property to ‘true’ </li></ul><ul><li>Set the value of the ‘Template Directory’ generator model property to the location of the custom templates </li></ul><ul><li>Dynamic templates can be customized in three ways </li></ul><ul><ul><li>Replacement </li></ul></ul><ul><ul><li>Insertions </li></ul></ul><ul><ul><li>Overrides </li></ul></ul>
  125. 125. Template Replacement <ul><li>Copy default template to the dynamic template directory (with the same name and relative location) and modify as desired </li></ul><ul><li>Modified template is compiled dynamically and used in place of the default template </li></ul><ul><li>Must keep in sync with changes in default templates (“clone and own”)… </li></ul>
  126. 126. Template Insertions <ul><li>Can insert content into default templates via insertion points identified using JET @include directive (fail=“silent”) </li></ul><ul><li>Dynamic template includes default template; insertions are included and compiled dynamically, result is used in place of the default template </li></ul><ul><li>By convention, insertions are placed in a folder named after the including template and end with a .insert.*jet extension </li></ul><ul><li>A number of insertion points have been defined for some commonly customized EMF templates (i.e. Class.javajet, ItemProvider.javajet, TestCase.javajet) </li></ul>
  127. 127. Template Overrides <ul><li>Can override content of default templates via override points identified using JET @include directive (fail=“alternative”) </li></ul><ul><li>Dynamic template includes default template; overrides are included and compiled dynamically, result is used in place of the default template </li></ul><ul><li>By convention, overrides are placed in a folder named after the including template and end with a .override.*jet extension </li></ul><ul><li>A number of override points have been defined for some commonly customized EMF templates (i.e. Class.javajet, ResourceFactoryClass.javajet, TestCase.javajet) </li></ul>
  128. 128. Template Insertions and Overrides <ul><li>Simplified example from Class.javajet: </li></ul><%@ include file=&quot;Class/genOperation.override.javajetinc&quot; fail=&quot;alternative&quot; %> <%@ start %> public <%=genOperation.getImportedType()%> <%=genOperation.getName()%>(...) { <%if (genOperation.hasBody()) {%> <%=genOperation.getBody(genModel.getIndentation(stringBuffer))%> ... <%} else {%> <%@ include file=&quot;Class/genOperation.TODO.override.javajetinc&quot; fail=&quot;alternative&quot; %> <%@ start %> // TODO: implement this method throw new UnsupportedOperationException(); <%@ end %> <%}%> } <%@ include file=&quot;Class/genOperation.insert.javajetinc&quot; fail=&quot;silent&quot; %> <%@ end %>
  129. 129. Generator Extension <ul><li>EMF’s generator is extensible </li></ul><ul><ul><li>Code generation is performed by visiting the elements in the model and invoking templates to generate artifacts for each element </li></ul></ul><ul><ul><li>Control over this process is delegated to GeneratorAdapters via one or more GeneratorAdapterFactory </li></ul></ul><ul><ul><li>Additional adapter factories can be plugged into the generator to create adapters that generate additional artifacts </li></ul></ul>
  130. 130. Generator Extension <ul><li>Contributing adapters via an extension point: </li></ul><ul><li>Adapters can be added directly, or via an adapter factory </li></ul><ul><li>A generic adapter factory is instantiated for each adapter added directly, so it’s more efficient to add multiple adapters via a factory </li></ul><extension point=&quot; org.eclipse.emf.codegen.ecore.generatorAdapters &quot;> < adapterFactory class=&quot;com.example.generator.MyGeneratorAdapterFactory&quot;/> < adapter modelClass=&quot;GenModel&quot; class=&quot;com.example.generator.MyGenModelGeneratorAdapter&quot;/> </extension>
  131. 131. Generator Model Extension <ul><li>It is possible, but not advised, to extend the generator model by subclassing its elements </li></ul><ul><ul><li>New attributes can be added to support additional code generation options </li></ul></ul><ul><ul><li>These attributes can be exposed as properties in the generator UI by registering a specialized adapter factory via the org.eclipse.emf.edit.itemProviderAdapterFacotries extension point </li></ul></ul><ul><ul><li>Protected members of GenModel elements are not considered API: you may have to adapt to changes in the base implementation! </li></ul></ul><ul><li>A better way to introduce new code generation options is using generator annotations </li></ul>
  132. 132. Going Deeper: GenAnnotations <ul><li>GenAnnotations can be added to any instance of GenBase, i.e. any object in a GenModel containment tree (including GenAnnotations themselves) </li></ul><ul><ul><li>GenBase provides two methods to work with GenAnnotations </li></ul></ul><ul><ul><ul><li>getGenAnnotations() </li></ul></ul></ul><ul><ul><ul><li>getGenAnnotation(String source) </li></ul></ul></ul><ul><li>A GenAnnotation, like its close relative EAnnotation, defines </li></ul><ul><ul><li>A source attribute, which is typically used to store a URI representing the type of the annotation </li></ul></ul><ul><ul><li>A details map attribute to store name-value pairs </li></ul></ul><ul><ul><li>Containment and non-containment references to EObjects </li></ul></ul>
  133. 133. Going Deeper: GenAnnotations <ul><li>The GenAnnotations are usually hidden in the Generator </li></ul><ul><ul><li>You can unhide them by checking &quot;Show Annotations&quot; in the &quot;Generator&quot; menu </li></ul></ul>
  134. 134. Agenda <ul><li>Working with Resources and ResourceSets </li></ul><ul><li>Customizing the Code Generator </li></ul><ul><li>Tuning for Performance and/or Memory Footprint </li></ul><ul><li>Importers and Exporters </li></ul><ul><li>Supporting Backward and Forward Compatibility </li></ul><ul><li>Summary </li></ul>
  135. 135. Performance/Memory Overhead <ul><li>EMF provides a number of mechanisms that can be used to tune the performance and/or memory overhead of your model implementation </li></ul><ul><li>Code Generator Options </li></ul><ul><ul><li>Boolean Flags </li></ul></ul><ul><ul><li>Virtual Feature Delegation </li></ul></ul><ul><ul><li>Minimal Reflective Methods </li></ul></ul><ul><li>XMLResource Options </li></ul>
  136. 136. Boolean Flags <ul><li>Generates code that uses (a) consolidated bit field(s) instead of separate fields to represent the values of Boolean attributes and whether unsettable features are set </li></ul><ul><li>Set the value of the ‘Boolean Flags Field’ generator model property to the name of the bit field(s) to be generated or reused </li></ul><ul><li>Set the value of the ‘Boolean Flags Reserved Bits’ generator model property to the number of bits in the field(s) that are reserved (e.g. used by parent classes) </li></ul><ul><li>Helps reduce memory overhead for models with a large number of Boolean attributes or unsettable features </li></ul>
  137. 137. Virtual Feature Delegation <ul><li>Generates code that uses a single, dynamically-allocated array field and associated index field(s) instead of separate fields to represent the values of non-primitive features </li></ul><ul><li>Set the value of the ‘Feature Delegation’ generator model property to ‘Virtual’ </li></ul><ul><li>Helps reduce memory overhead for models with a large number of features that are often “sparsely” used </li></ul>
  138. 138. Minimal Reflective Methods <ul><li>Generates reflective methods that delegate to super , i.e. they delegate switching for any non-matching features to the superclass implementation for dispatching </li></ul><ul><li>Set the value of the ‘Minimal Reflective Methods’ generator model property to ‘true’ (default) </li></ul><ul><li>Helps reduce memory (byte code) overhead for models with a large number of inherited features </li></ul><ul><li>May increase performance overhead for models with deep class hierarchies </li></ul>
  139. 139. XMLResource Options <ul><li>XMLResource offers a set of options that can be used to tweak load and save behavior </li></ul><ul><li>The options are passed to the resource’s save and load methods as entries in a map </li></ul><ul><ul><li>The key is the constant that represents the option </li></ul></ul><ul><ul><li>Each option requires an appropriate value </li></ul></ul>
  140. 140. XMLResource Load Options <ul><li>OPTION_DEFER_IDREF_RESOLUTION </li></ul><ul><ul><li>Option value: Boolean </li></ul></ul><ul><ul><li>Defers resolving references within a resource until the whole document has been parsed </li></ul></ul><ul><li>OPTION_USE_PARSER_POOL </li></ul><ul><ul><li>Option value: org.eclipse.emf.ecore.xmi.XMLParserPool </li></ul></ul><ul><ul><li>Provides a parser pool, from which SAXParser instances are created and reused </li></ul></ul><ul><li>OPTION_USE_XML_NAME_TO_FEATURE_MAP </li></ul><ul><ul><li>Option value: java.util.Map </li></ul></ul><ul><ul><li>Enables sharing the cache of mappings between qualified XML names (namespace + local name) and corresponding Ecore features across invocations of load(…), or even among resources </li></ul></ul>
  141. 141. XMLResource Load Options <ul><li>OPTION_USE_CACHED_LOOKUP_TABLE </li></ul><ul><ul><li>Option value: java.util.List </li></ul></ul><ul><ul><li>Specifies a list as a place holder for caching information during the subsequent saving of XML documents </li></ul></ul><ul><li>OPTION_USE_DEPRECATED_METHODS </li></ul><ul><ul><li>Option value: Boolean </li></ul></ul><ul><ul><li>Use methods that were deprecated in EMF </li></ul></ul><ul><ul><li>The default value is Boolean.TRUE </li></ul></ul>
  142. 142. XMLResource Save Options <ul><li>OPTION_FLUSH_THRESHOLD </li></ul><ul><ul><li>Option value: Integer </li></ul></ul><ul><ul><li>Specifies a maximum number of characters to allow in the output stream before flushing it </li></ul></ul><ul><li>OPTION_USE_CACHED_LOOKUP_TABLE </li></ul><ul><ul><li>Option value: java.util.List </li></ul></ul><ul><ul><li>Provides a placeholder to cache information about structure of the model (using qualified XML names as a key for caching information) </li></ul></ul><ul><li>OPTION_CONFIGURATION_CACHE </li></ul><ul><ul><li>Option value: Boolean </li></ul></ul><ul><ul><li>Enables caching and reusing generic data in repeated save operations, avoiding the cost of reinitializing the data </li></ul></ul>
  143. 143. XMLResource Save Options <ul><li>OPTION_FORMATTED </li></ul><ul><ul><li>Option value: Boolean </li></ul></ul><ul><ul><li>Disables formatting of documents, omitting whitespaces and line brakes, to improve the performance of saving and, subsequently, loading the resulting document </li></ul></ul><ul><li>OPTION_USE_FILE_BUFFER </li></ul><ul><ul><li>Option value: Boolean </li></ul></ul><ul><ul><li>Enables accumulating output during serialization in a temporary file, rather than an in-memory buffer </li></ul></ul>
  144. 144. Agenda <ul><li>Working with Resources and ResourceSets </li></ul><ul><li>Customizing the Code Generator </li></ul><ul><li>Tuning for Performance and/or Memory Footprint </li></ul><ul><li>Importers and Exporters </li></ul><ul><li>Supporting Backward and Forward Compatibility </li></ul><ul><li>Summary </li></ul>
  145. 145. Importers and Exporters Java model Annotated Java Model Importer EMF Model Exporter Java model UML Java model XML Schema Java model Ecore Java model ? Java model ? Java model XML Schema Java model XML Schema for XMI
  146. 146. Model Importers <ul><li>A Model Importer (aka an importer) is responsible for creating an Ecore model from the description of a modeled domain </li></ul><ul><ul><li>Each importer knows how to handle a specific format of description </li></ul></ul><ul><ul><li>An importer is also expected to create the generator model (.genmodel file) for the Ecore Model (.ecore file) </li></ul></ul><ul><li>EMF provides importers that handle the following formats </li></ul><ul><ul><li>Rational Rose models </li></ul></ul><ul><ul><li>XML Schemas </li></ul></ul><ul><ul><li>Annotated Java Interfaces </li></ul></ul><ul><ul><li>Ecore and EMOF files </li></ul></ul>
  147. 147. Model Exporters <ul><li>A Model Exporter (aka exporter) is able to read an Ecore model and generate another description of the same modeled domain </li></ul><ul><ul><li>An exporter typically uses the information described in the Generator Model to accomplish its purposes </li></ul></ul><ul><li>EMF provides two exporters </li></ul><ul><ul><li>XML Schema </li></ul></ul><ul><ul><li>XML Schema for XMI </li></ul></ul><ul><li>EMF also provides an HTML exporter example, which uses JET to produce a package summary </li></ul>
  148. 148. Going Deeper: Why is the Generator Model so important? <ul><li>The generator model acts as a decorator for an Ecore model </li></ul><ul><ul><li>It provides details that would pollute the model, such as the </li></ul></ul><ul><ul><ul><li>Qualified name of an EPackage </li></ul></ul></ul><ul><ul><ul><li>Prefix for package-related class names </li></ul></ul></ul><ul><ul><ul><li>Actual location of the model, edit, editor, and test source folders </li></ul></ul></ul><ul><li>When a modeled domain is converted into an EMF model, the importer may be able to capture some generator model details and store them in a .genmodel file </li></ul><ul><ul><li>The Java package of the annotated Java interfaces </li></ul></ul><ul><ul><li>Referenced XML Schemas that may or may not be already represented by Ecore models </li></ul></ul><ul><li>The generator model is useful to an exporter because </li></ul><ul><ul><li>It can be used to persist details about the exported artifact </li></ul></ul><ul><ul><li>Some details may be important to properly describe the modeled domain </li></ul></ul>
  149. 149. Using Importers and Exporters <ul><li>The importers and exporters are presented to the user as pages of a standard EMF wizard </li></ul><ul><ul><li>The registered importers are presented during the execution of the new EMF model or EMF project wizards </li></ul></ul><ul><ul><li>The list of exporters is shown when the “Export Model…” action is invoked on a .genmodel file </li></ul></ul><ul><ul><li>The motivation of this design is to let the importers and exporters decide the input that the user needs to provide </li></ul></ul><ul><ul><ul><li>Each implementation has total control over the number of pages of the wizard and their content </li></ul></ul></ul><ul><li>The Rose and XML Schema importers are also available as Eclipse applications and Ant tasks </li></ul>
  150. 150. Contributing an Importer via an Extension Point <ul><li>The wizard must be a class that implements EMF’s IModelImporterWizard interface </li></ul><ul><ul><li>Defines the setters that will be used by the new EMF model and project wizards to communicate the details about the model specification being imported </li></ul></ul><extension point=&quot; org.eclipse.emf.importer.modelImporterDescriptors &quot;> <modelImporterDescriptor id =&quot;com.mycompany.ModelImporterDescriptor.XYZ&quot; name=&quot;XYZ class model&quot; extensions=&quot;xyz&quot; wizard =&quot;com.mycompany.ImportWizard&quot;/> </extension>
  151. 151. Contributing an Exporter via an Extension Point <ul><li>The wizard must be a class that implements Eclipse’s IWorkbenchWizard interface </li></ul><ul><ul><li>The first time the wizard is presented to the user, the method init(IWorkbench, IStructuredSelection) is invoked and the selection argument is either an IFile that contains the generator model or an instance of GenModel </li></ul></ul><extension point=&quot; org.eclipse.emf.importer.modelExporterDescriptors &quot;> <modelExporterDescriptor id =&quot;com.mycompany.ModelExporterDescriptor.XYZ&quot; name=&quot;XYZ class model&quot; wizard =&quot;com.mycompany.ExportWizard&quot;/> </extension>
  152. 152. Contributing Importers and Exporters via Global Registries <ul><li>The idea is to add the importer/exporter description to the appropriate list </li></ul><ul><ul><li>ModelImporterManager.INSTANCE.getModelConverterDescriptors() </li></ul></ul><ul><ul><li>ModelExporterManager.INSTANCE.getModelConverterDescriptors() </li></ul></ul><ul><li>The importer and exporter descriptions are quite similar, which led to the creation of a common parent interface </li></ul>
  153. 153. Agenda <ul><li>Working with Resources and ResourceSets </li></ul><ul><li>Customizing the Code Generator </li></ul><ul><li>Tuning for Performance and/or Memory Footprint </li></ul><ul><li>Importers and Exporters </li></ul><ul><li>Supporting Backward and Forward Compatibility </li></ul><ul><li>Summary </li></ul>
  154. 154. Backward/Forward Compatibility <ul><li>EMF provides mechanisms that can be used to support migration of data between different versions of a model (or between two different models, for that matter): </li></ul><ul><ul><li>Use Ecore2Ecore and Ecore2XML to define a mapping between the different model(s) (versions) </li></ul></ul><ul><ul><li>Use Ecore2XMLExtendedMetaData with save/load options to handle unrecognized data </li></ul></ul><ul><ul><li>Use a resource handler to pre/post-process data that cannot be mapped automatically </li></ul></ul><ul><li>Source and target models must have different namespace URIs and XML references must not be based on feature names </li></ul>
  155. 155. Ecore2Ecore Mappings <ul><li>Describe a mapping between two Ecore models </li></ul><ul><li>Can be created from an Ecore (*.ecore) model via the ‘Map To Ecore…’ context menu item in the Package Explorer or Resource Navigator </li></ul><ul><li>Typically used as a development-time artifact (only) </li></ul><ul><li>Can include one-to-one, one-to-many, many-to-one, many-to-many, and one-sided mappings </li></ul><ul><li>Only one-to-one and one-sided (one-to-none, none-to-one) mappings are useful for data migration </li></ul>
  156. 156. Ecore2XML Mappings <ul><li>Describe a mapping between an Ecore model and its XML representation </li></ul><ul><li>Can be generated from an Ecore2Ecore (*.ecore2ecore) model via the ‘Generate Ecore to XML Mapping…’ context menu item in the Package Explorer or Resource Navigator </li></ul><ul><li>Often used as a run-time artifact (in conjunction with Ecore2XMLExtendedMetaData) </li></ul><ul><li>Can include one-to-one and many-to-one mappings, but only the former are useful for data migration </li></ul>
  157. 157. Ecore2XMLExtendedMetaData <ul><li>Can be used with the OPTION_EXTENDED_META_DATA save/load option defined on XMLResource to affect how data are serialized/deserialized </li></ul><ul><li>Will consult registered Ecore2XML mappings to determine the XML representation of objects </li></ul>my.y my.x x_2_y.ecore2xml
  158. 158. OPTION_RECORD_UNKNOWN_FEATURE <ul><li>Load option defined on XMLResource </li></ul><ul><li>Will record data for unrecognized types and features in an extension map (XMLResource#getEObjectToExtensionMap()) on the resource </li></ul><ul><li>Recorded data will be serialized again when the resource is saved (unless the entries in the map have been cleared) </li></ul>my.x my.y y => x
  159. 159. Resource Handlers <ul><li>Interface XMLResource.ResourceHandler defines callbacks that can be implemented to do special processing before/after a resource is loaded/saved </li></ul><ul><li>Used with OPTION_RESOURCE_HANDLER save/load option defined on XMLResource </li></ul><ul><li>Can support backward compatibility by extracting data from a resource’s extension map after it is loaded </li></ul><ul><li>Can support forward compatibility by inserting data into a resource’s extension map before it is saved </li></ul>
  160. 160. Enabling Data Migration <ul><li>Create a package registry and add entries which map the source namespace URI and target Ecore model location to the target package </li></ul><ul><li>Create an Ecore2XML registry and add an entry which maps the source namespace URI to the Ecore2XML mapping </li></ul><ul><li>Create an instance of Ecore2XMLExtendedMetaData based on the package and Ecore2XML registries; pass this extended metadata as the value for the XMLResource.OPTION_EXTENDED_META_DATA load/save option </li></ul>
  161. 161. Enabling Data Migration <ul><li>Pass Boolean.TRUE as the value for the XMLResource.OPTION_RECORD_UNKNOWN_FEATURE load option </li></ul><ul><li>If required, pass an implementation of XMLResource.ResourceHandler as the value for the XMLResource.OPTION_RESOURCE_HANDLER load/save option </li></ul>
  162. 162. Agenda <ul><li>Working with Resources and ResourceSets </li></ul><ul><li>Customizing the Code Generator </li></ul><ul><li>Tuning for Performance and/or Memory Footprint </li></ul><ul><li>Importers and Exporters </li></ul><ul><li>Supporting Backward and Forward Compatibility </li></ul><ul><li>Summary </li></ul>
  163. 163. Summary <ul><li>We have seen examples of how flexible and extensible the Eclipse Modeling Framework is </li></ul><ul><li>Hopefully you have gained greater insight into how some of the more “advanced” features of EMF can be exploited to meet your application’s needs </li></ul>
  164. 164. Part 3: Eclipse Modeling Framework Technologies – Query, Transaction, Validation
  165. 165. Agenda <ul><li>EMFT in a Nutshell </li></ul><ul><li>Validating Models </li></ul><ul><li>Querying Models </li></ul><ul><li>Working with Transactions </li></ul><ul><li>Working with the Operation History </li></ul><ul><li>Summary </li></ul>
  166. 166. What is EMFT? <ul><li>A collection of components that “add on” to EMF to provide value-added capabilities for rich applications </li></ul><ul><li>Currently includes: </li></ul><ul><ul><li>Validation – a flexible framework for contributing 3 rd -party constraints to model validation </li></ul></ul><ul><ul><li>Query – an SQL-like Java API for querying EMF resources </li></ul></ul><ul><ul><li>Transaction – a transaction protocol for concurrent access to EMF resources </li></ul></ul><ul><ul><li>CDO, Teneo – object-relational mappings for persistence of EMF resources in RDBMSes </li></ul></ul><ul><ul><li>JET Editor – a rich editor for JET templates </li></ul></ul>
  167. 167. What was EMFT? <ul><li>Formerly in EMFT: </li></ul><ul><ul><li>OCL – an implementation of the Object Constraint Language for Ecore and UML metamodels; now a component of MDT </li></ul></ul><ul><ul><li>EODM – an implementation of the Ontology Definition Metamodel for Ecore; now a component of MDT </li></ul></ul><ul><ul><li>JET (a.k.a. JET2) – next generation of the Java Emitter Templates; now a component of M2T </li></ul></ul><ul><li>This tutorial will explore the Validation, Query, and Transaction components with a little OCL added for flavour </li></ul>
  168. 168. What does the Validation Framework Provide? <ul><li>Extensibility: </li></ul><ul><ul><li>Constraint providers contribute constraints from any source they deem fit, including the plugin.xml, constraints embedded in models, or external models </li></ul></ul><ul><ul><li>Constraint parsers contribute support for constraint specification languages. Out of the box, the framework implements Java and OCL support. </li></ul></ul><ul><ul><li>Traversal strategies contribute knowledge of the model structure and how to discover its extent to validate it </li></ul></ul><ul><ul><li>Constraint categories and bindings help to organize constraints and activate them in specific applications </li></ul></ul><ul><ul><li>Validation listeners are notified whenever validation occurs, to provide an appropriate response from the application </li></ul></ul>
  169. 169. What does the Validation Framework Provide? <ul><li>Invocation (Triggers) </li></ul><ul><ul><li>“Batch” validation: initiated by the user or by the system on some important event, validates all or a selected subset of a model </li></ul></ul><ul><ul><li>“Live” validation: initiated automatically by the system to validate a set of changes performed during some transaction. The semantics of “transaction” are defined by the client </li></ul></ul><ul><ul><ul><li>Constraints can specify which particular changes trigger them (by feature and event type) </li></ul></ul></ul><ul><li>Support for OCL constraints </li></ul><ul><ul><li>EMFT Validation uses the OCL component of the MDT project to provide out-of-box support for specifying constraints using OCL </li></ul></ul>
  170. 170. What does the Query Framework Provide? <ul><li>A convenient Java API for querying an EMF-based model </li></ul><ul><ul><li>The API is designed to look and feel like SQL, with SELECT and UPDATE statements, FROM clauses, etc. </li></ul></ul><ul><ul><li>Offers a wide array of reusable and recombinable predicate objects for specifying WHERE clause conditions </li></ul></ul><ul><ul><li>Supports nested and compound queries </li></ul></ul><ul><ul><li>Easily customizable for special requirements in traversing models, etc. </li></ul></ul><ul><li>Support for OCL </li></ul><ul><ul><li>Provides predicate classes that specify WHERE conditions as OCL constraints (with context or, optionally, context-free) </li></ul></ul>
  171. 171. What does the Transaction API Provide? <ul><li>A transactional editing environment </li></ul><ul><ul><li>Safe read and write access to EMF resources from multiple concurrent threads </li></ul></ul><ul><ul><li>Commit protocol providing mechanisms for ensuring model integrity: </li></ul></ul><ul><ul><ul><li>Validation of the changes performed during the transaction (constraints) using the Validation Framework </li></ul></ul></ul><ul><ul><ul><li>Pre-commit listeners proactively performing concomitant changes (triggers) to maintain consistency of dependencies </li></ul></ul></ul><ul><ul><ul><li>Automatic rollback of changes on failure to validate or complete triggers </li></ul></ul></ul><ul><ul><ul><li>Supports transaction nesting </li></ul></ul></ul>
  172. 172. What does the Transaction API Provide? <ul><li>Read/write transactions </li></ul><ul><ul><li>Give a thread exclusive access to a ResourceSet for the purpose of modifying its content </li></ul></ul><ul><ul><li>Ensure that other threads do not observe interim (uncommitted) states of the data (“dirty reads”) </li></ul></ul><ul><li>Read-only transactions </li></ul><ul><ul><li>Protect against threads concurrently initializing concrete state of the ResourceSet (such as duplicate resolution of proxies or duplicate initialization of ELists) </li></ul></ul><ul><ul><li>Can be shared cooperatively by multiple reading threads </li></ul></ul>
  173. 173. What does the Transaction API Provide? <ul><li>Change events </li></ul><ul><ul><li>Commit of a transaction sends a ResourceSetChangeEvent to interested listeners, with a summary of the changes that the transaction performed </li></ul></ul><ul><ul><li>Changes are sent as a single batch, and only on successful commit, so that UI refreshes etc. don’t get any “noise” </li></ul></ul><ul><li>Integration with Eclipse Workbench APIs </li></ul><ul><ul><li>Support for delegating the EMF CommandStack to an IOperationHistory </li></ul></ul><ul><ul><li>Leverages the IUndoContext to support separate undo/redo “stacks” where independent changes occur in a single ResourceSet </li></ul></ul>
  174. 174. Agenda <ul><li>EMFT in a Nutshell </li></ul><ul><li>Validating Models </li></ul><ul><li>Querying Models </li></ul><ul><li>Working with Transactions </li></ul><ul><li>Working with the Operation History </li></ul><ul><li>Summary </li></ul>
  175. 175. Constraint Providers <ul><li>Constraint providers are of two flavours: static and dynamic </li></ul><ul><ul><li>Static providers declare their constraints in the plugin.xml of a client plug-in of the constrained model </li></ul></ul><ul><ul><li>Dynamic providers obtain constraints from an arbitrary source at run-time </li></ul></ul><ul><li>Both kinds of providers can declare constraint categories and include their constraints in categories defined by any provider </li></ul><ul><ul><li>Categories are hierarchical namespaces for constraints </li></ul></ul><ul><ul><li>Constraints are grouped by category in the preference page </li></ul></ul>
  176. 176. Static Constraint Provider <extension point=&quot; org.eclipse.emf.validation.constraintProviders &quot;> < category name =&quot;Library Constraints&quot; id =&quot;com.example.library&quot;> <constraintProvider> < package namespaceUri =&quot;http:///;/> <constraints categories =&quot;com.example.library&quot;> <constraint lang =&quot;Java&quot; class =&quot;com.example.constraints.UniqueLibraryName&quot; severity =&quot;WARNING&quot; mode =&quot;Batch&quot; name=&quot;Library Must have a Unique Name&quot; id=&quot;com.example.library.LibraryNameIsUnique&quot; statusCode=&quot;1&quot;> <description>Libraries have unique names.</description> <message>{0} has the same name as another library.</message> < target class =&quot;Library&quot;/> </constraint> </constraints> </constraintProvider> </extension>
  177. 177. Dynamic Constraint Provider <ul><li>Registered by name of a class implementing the IModelConstraintProvider interface </li></ul><ul><li>Indicate the packages for which they supply constraints </li></ul><ul><ul><li>Biggest difference is the absence of a <constraints> element </li></ul></ul><ul><li>System can optionally cache the provided constraints </li></ul><extension point=&quot; org.eclipse.emf.validation.constraintProviders &quot;> < category name =&quot;Library Constraints&quot; id =&quot;com.example.library&quot;> <constraintProvider class =&quot;com.example.MyConstraintProvider&quot; cache =&quot;false&quot;> < package namespaceUri =&quot;http:///;/> </constraintProvider> </extension>
  178. 178. Dynamic Constraint Provider <ul><li>A dynamic constraint provider implements the IModelConstraintProvider interface </li></ul><ul><li>A descriptor supplies meta-data about a constraint </li></ul><ul><li>The validation algorithm is supplied by the constraint object in the validate() method </li></ul>
  179. 179. Constraints <ul><li>Descriptor provides: </li></ul><ul><ul><li>ID and localizable name </li></ul></ul><ul><ul><li>Evaluation mode </li></ul></ul><ul><ul><li>Target EClasses </li></ul></ul><ul><ul><li>Triggering events (live) </li></ul></ul><ul><ul><li>Severity, error message </li></ul></ul><ul><ul><li>Categorization </li></ul></ul><ul><ul><li>Enabled state </li></ul></ul><ul><li>Much of this information appears in the preference page </li></ul><ul><li>Users can choose which constraints to activate </li></ul>
  180. 180. Evaluation Modes <ul><li>Batch validation is usually explicitly requested by the user, via a menu action or toolbar button </li></ul><ul><li>Live validation is performed automatically as changes are made to EMF resources </li></ul><ul><ul><li>Live constraints indicate which specific changes trigger them </li></ul></ul><constraint mode =&quot;Live&quot; … > <description>Libraries have unique names.</description> <message>{0} has the same name as: {1}.</message> <target class=&quot;Library&quot;> < event name =&quot;Set&quot;> < feature name =&quot;name&quot;/> </ event > </target> </constraint>
  181. 181. Validation Service <ul><li>Evaluation of constraints is performed via the Validation Service </li></ul><ul><li>The service provides validators corresponding to the available evaluation modes </li></ul><ul><li>By default, batch validation includes live constraints, also, for completeness </li></ul>
  182. 182. Validation Service <ul><li>To validate one or more elements, in batch mode, simply create a new validator and ask it to validate: </li></ul>List objects = myResource.getContents(); // objects to validate // create a validator IValidator validator = ModelValidationService.getInstance() . newValidator (EvaluationMode. BATCH ); // use it! IStatus results = validator. validate (objects); if (!results.isOK()) { ErrorDialog.openError(null, &quot;Validation&quot;, &quot;Validation Failed&quot;, results); }
  183. 183. Validation Service <ul><li>Live validation does not validate objects, but rather Notification s indicating changes to objects </li></ul>List< Notification > notifications = … ; // some changes that we observed // create a validator IValidator validator = ModelValidationService.getInstance() .newValidator(EvaluationMode. LIVE ); // use it! IStatus results = validator.validate( notifications ); if (!results.isOK()) { ErrorDialog.openError(null, &quot;Validation&quot;, &quot;Validation Failed&quot;, results); }
  184. 184. Creating Constraints <ul><li>Specifying a constraint doesn’t necessarily require any code </li></ul><ul><li>Requires the OCL component of the MDT project </li></ul><constraint lang=&quot; OCL &quot; mode=&quot;Batch&quot; … > <description>Libraries have unique names.</description> <message>{0} has the same name as: {1}.</message> <target class=&quot;Library&quot;/> <![CDATA[ Library.allInstances()->forAll(l | l <> self implies <> ]]> </constraint>
  185. 185. Creating Constraints <ul><li>Sometimes the easiest or best way to formulate a constraint is in Java </li></ul><ul><li>Java constraints extend the AbstractModelConstraint class </li></ul><ul><li>The validation context provides the validate() method with information about the validation operation </li></ul>
  186. 186. Validation Context <ul><li>Provides the element being validated (the target) </li></ul><ul><li>Indicates the current evaluation mode (live or batch) </li></ul><ul><ul><li>In case of live invocation, provides the changed feature and the event type </li></ul></ul><ul><li>Allows constraints to cache arbitrary data for the duration of the current validation operation </li></ul><ul><li>Provides convenient methods for reporting results </li></ul><ul><li>Provides the ID of the constraint that is being invoked </li></ul>
  187. 187. Creating Constraints public class LibraryNameIsUnique extends AbstractConstraint { public IStatus validate (IValidationContext ctx) { Library target = (Library) ctx. getTarget (); // object to validate // does this library have a unique name? Set<Library> libs = findLibrariesWithName(target.getName()); if (libs.size() > 1) { // report this problem against all like-named libraries ctx. addResults (libs); // don’t need to validate these other libraries libs.remove(target); ctx. skipCurrentConstraintFor (libs); return ctx.createFailureStatus(new Object[] { target, libs}); } return ctx. createSuccessStatus (); } }
  188. 188. Listening for Validation Events <ul><li>Every validation operation executed by the Validation Service generates an event </li></ul><ul><li>The event indicates the kind of validation performed, on what objects, and what were the results (incl. severity) </li></ul><ul><li>Listeners registered on the extension point are lazily initialized when their selection criteria are met </li></ul><extension point=&quot; org.eclipse.emf.validation.validationListeners &quot;> < listener class =&quot;com.example.validation.ProblemsReporter&quot;> < clientContext id =&quot;com.example.MyClientContext&quot;/> </listener> </extension>
  189. 189. Reporting Problems <ul><li>Problems are reported as IConstraintStatus objects. A status knows: </li></ul><ul><ul><li>The constraint that was violated </li></ul></ul><ul><ul><li>The objects that violated it </li></ul></ul><ul><ul><li>The severity and error message, as usual for an IStatus </li></ul></ul><ul><li>The marker utility encodes all of this information in a problem marker on the appropriate resource, to show in the Problems view </li></ul>
  190. 190. Reporting Problems public class ProblemsReporter implements IValidationListener { public void validationOccurred (ValidationEvent event) { if (event. matches (IStatus.WARNING | IStatus.ERROR)) { // fabricate a multi-status for the MarkerUtil to consume List results = event. getValidationResults (); IConstraintStatus multi = new MultiStatus( &quot;com.example.MyPlugin&quot;, 1, (IStatus[])results.toArray(new IStatus[results.size()]), &quot;Problems were found by validation&quot;, null); try { // create problem markers on the appropriate resources MarkerUtil.createMarkers (multi); } catch ( CoreException e ) { // creation of problem markers failed for some reason MyPlugin.getLog().log(e.getStatus()); } } } }
  191. 191. Agenda <ul><li>EMFT in a Nutshell </li></ul><ul><li>Validating Models </li></ul><ul><li>Querying Models </li></ul><ul><li>Working with Transactions </li></ul><ul><li>Working with the Operation History </li></ul><ul><li>Summary </li></ul>
  192. 192. Query Statements <ul><li>SELECT statements filter the objects provided by a FROM clause according to the conditions specified in the WHERE clause </li></ul><ul><li>SELECT s are IEObjectSource s, so they can be used in FROM clauses to nest queries </li></ul><ul><li>UPDATE statements use a SET clause to update the objects provided by the FROM clause (filtered, of course, by the WHERE clause) </li></ul>
  193. 193. The FROM Clause <ul><li>Uses EMF’s tree iterators to walk the objects being queried </li></ul><ul><li>Optionally specifies an EObjectCondition filter </li></ul><ul><li>Search scope is encapsulated in an IEObjectSource </li></ul><ul><ul><li>provides objects via an iterator. The FROM descends into the contents of these objects if it is a hierarchical IteratorKind </li></ul></ul>
  194. 194. The WHERE Clause <ul><li>The WHERE clause specifies a single filter condition </li></ul><ul><li>This filter condition can be arbitrarily complex </li></ul><ul><li>Filters can be combined in innumerable ways using