Your SlideShare is downloading. ×
EclipseCon 2007: Effective Use of the Eclipse Modeling Framework
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

EclipseCon 2007: Effective Use of the Eclipse Modeling Framework

3,025

Published on

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

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

Published in: Technology
1 Comment
11 Likes
Statistics
Notes
No Downloads
Views
Total Views
3,025
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
0
Comments
1
Likes
11
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • You will also need to: - manually change the JDK compliance level in the Java Compiler project properties or workspace preferences - Update the JRE container in the project’s classpath (use the Plug-in Manifest Editor: on the overview page, select “Update the classpath settings”)
  • Inverse References - Finding the opposite of a unidirectional association
  • Initially the arrows are proxies and when the references in Resource1 are resolved, they are replaced by the actual object from Resource2. The 2 nd proxy will be a proxy until it is accessed. When the 1 st proxy is resolved Resource2 is loaded into the ResourceSet but that doesn’t resolve all the proxies.
  • The cross referencers check the containment tree of an EObject. Make it clear that a proxy is not “referenced” – this is a “transient” state.
  • ECoreUtil.CrossReferencer is a convenient utility class for locating cross-references (that is, non-containment references) in the containment tree, or trees, rooted at a specified EMF object, resource, or resource set, or arbitrary collection of all three. The result of the search is stored in the cross-referencer’s base HashMap. Entries are keyed by reference targets, and their values are the collections of EStructuralFeature.Settings that identify all the source object-feature pairs referencing the keyed target. ECoreUtil.ExternalCrossReferencer is a convenient utility class for locating external cross-references in the containment tree, or trees, rooted at a specified EMF object, resource, or resource set, or arbitrary collection of all three. An external cross-reference is one that has a target that is not within the containment structure rooted at the object(s) being searched. ECoreUtil.ProxyCrossReferencer is a convenient utility class for locating proxies in the containment tree, or trees, rooted at a specified EMF object, resource, or resource set, or arbitrary collection of all three. ECoreUtil.UnresolvedProxyCrossReferencer is a convenient utility class for locating unresolvable (broken) proxies in the containment tree, or trees, rooted at a specified EMF object, resource, or resource set, or arbitrary collection of all three. ECoreUtil.UsageCrossReferencer is a convenient utility class for locating cross-references in the containment tree, or trees, rooted at a specified EMF object, resource, or resource set, or arbitrary collection of all three, with targets that are specific objects of interest. One or more objects of interest can be passed to the static find() or findAll() methods, respectively, which in turn construct an instance, with the search root(s), and then call their corresponding findUsage() or findAllUsage() instance methods.
  • Is exposed on InternalEObject
  • Explains why the name “CrossReferencer”. This is an informal qualification.
  • As explained in the “Introduction to EMF” tutorial, the EObjectValidator is used as base of generated validators and directly for packages without additional constraints defined.
  • Not always can we choose the “proxy handling” option we would like to…
  • Formatted string: /, encoded, … Encoding is done by Converting the character string into a sequence of bytes using UTF-8 Convert each character that is not an ASCII letter or digit into %HH, where HH is the hexadecimal value of the byte URL: Resources that can be accessed with existing protocols URN: “Intended to serve as persistent, location-independent, resource identifiers” oasis urn: http://rfc3121.x42.com/
  • URI.encodeFragment(String) can be used to produce a valid fragment.
  • The default value of the “Resolve Proxies” attribute in an Ecore model is true.
  • We could also call book.eContainer().eResource.getURI() instead of just library.eResource().getURI(), to illustrate that the book hasn't been removed from its container (although, that's kind of obvious from the fact that it ends up back in the same resource as the library)…
  • Should also mention generated editor support for containment proxies (Control / Uncontrol menu items)…
  • The question we want to answer is: what books were written by Dave? We could also use the UsageCrossReferencer…
  • Why are we not defining what an ECrossReferenceAdapter is? Because we (should) know what a CrossReferencer and an Adapter are…
  • The question we want to answer is: what books were written by Dave?
  • This is not used by the generated UI to decided whether an editor is dirty or not - EMF.Edit monitors the state of the command stack of the EditingDomain…
  • Resource.Internal, like InternalEObject and EStructuralFeature.Internal, is not really an “internal” API – it’s an API of less commonly used implementation oriented methods… all resources are assumed to implement this interface, and do so by virtue of extending ResourceImpl.
  • Generates implementation classes without separate interface declarations Set the value of the ‘Suppress Interfaces’ generator model property to ‘true’
  • Generates code without a package interface declaring metadata accessors and constants - these are generated into the package implementation, instead - Factory doesn’t extend EFactory Set the value of the ‘Suppress EMF Meta Data’ generator model property to ‘true’
  • Generates code where interfaces for modeled root classes extend a specified interface, or nothing at all Clear or set the value of the ‘Root Extends Interface’ generator model property - Qualified name of interface, which need not extend EObject
  • Generates code without @model tags in the Javadoc Set the value of the ‘Suppress EMF Model Tags’ generator model property to ‘true’
  • Generates methods for features and operations which use standard Java collection and object types instead of those from EMF (e.g. EList, EMap, EObject) Set the value of the ‘Suppress EMF Types’ generator model property to ‘true’
  • Header.javajetinc is an example of a template that should perhaps always be replaced – to contain your copyright.
  • Dynamic “placeholder” template can also add required imports for compiling the template (in case the insertions reference new types). Need to reference default template “container” in JET project settings – i.e. templates;@/org.eclipse.emf.codegen.ecore/templates.
  • Dynamic “placeholder” template can also add required imports for compiling the template (in case the overrides reference new types). Need to reference default template “container” in JET project settings – i.e. templates;@/org.eclipse.emf.codegen.ecore/templates.
  • Of course, there is always a trade-off between time and space concerns…
  • Of course, virtual feature delegation has a (significant) performance cost. We are also working on a VirtualEObjectImpl which will use virtual slots instead of a properties holder…
  • OPTION_DEFER_IDREF_RESOLUTION Option value: Boolean This option can be enabled to defer resolving references within a resource until the whole document has been parsed. The default strategy is to try to resolve each reference as it is encountered and then, at the end, resolve any ones that failed. This wastes time looking up forward references that do not exist yet, which, if you're using intrinsic IDs, can involve iterating over every object in the resource. OPTION_USE_PARSER_POOL Option value: org.eclipse.emf.ecore.xmi.XMLParserPool We strongly encourage to set this option for EMF load operation. This option is used to provide a parser pool, from which SAXParser instances are created and reused. XMLParserPool defines a simple interface for obtaining and releasing parsers based on their features and properties. Specifying a parser pool, such as an instance of the default implementation, XMLParserPoolImpl, can improve performance dramatically when a resource performs repeated loads. A single parser pool can also be shared among multiple resources. Default implementation is also thread-safe. OPTION_USE_XML_NAME_TO_FEATURE_MAP Option value: java.util.Map This option can be used to share the cache of mappings between qualified XML names (namespace + local name) and corresponding Ecore features across invocations of load(), or even among resources. It can take some time to determine these associations, since they can be affected by ExtendedMetaData or an XMLMap, so they are cached during a load. If you use this option to specify the same map for several loads, that instance will be used as the cache, improving the performance for all but the first. You can share a single map among multiple resources, unless they load different models with conflicting qualified names.
  • OPTION_USE_CACHED_LOOKUP_TABLE Option value: java.util.List Specify a list as a place holder for caching information during the subsequent saving of XML documents. This option can improve performance for serialization (saving) of multiple XML resources. This option is similar to the OPTION_USE_XML_NAME_TO_FEATURE_MAP which is used for deserialization (loading). OPTION_USE_DEPRECATED_METHODS Option value: Boolean Use methods that were deprecated in EMF. The default value is true. To improve deserialization performance turn this option to false. The methods affected are: XMLHelper#createObject(org.eclipse.emf.ecore.EFactory, EClassifier) XMLHander#handleNamespaceAttribs() XMLHandler#createObjectFromFactory(EFactory factory, String typeName) XMLLoadImpl#getEncoding() Note: if you use this option the SAX parser used for parsing documents must be namespace-aware parser, i.e. the namespaces should be turned on for the parser used. The default parser implementation is not namespace-aware. To turn on namespaces, either use OPTION_USE_PARSER_POOL or overwrite XMLLoadImpl#makeParser()
  • OPTION_FLUSH_THRESHOLD Option value: Integer This option can be used to specify a maximum number of characters to allow in the output stream before flushing it. This reduces the memory used in serializing a large file, but it is slower than the default behavior. OPTION_USE_CACHED_LOOKUP_TABLE Option value: java.util.List This option provides a placeholder to cache information about structure of the model. (using qualified XML names as a key for caching information). When possible, the same placeholder list should be shared among resources, unless you intent to serialize instances of different models. OPTION_CONFIGURATION_CACHE Option value: Boolean This option can be enabled to cache and reuse generic data in repeated save operations, avoiding the cost of reinitializing the data. This option is save to use when serializing instances of the same model.
  • OPTION_FORMATTED Option value: Boolean This option is used to disable formatting of documents, omitting whitespaces and line brakes, to improve the performance of saving and, subsequently, loading the resulting document. This means fewer bytes have to be written and read, but the serialization will be less human-readable. OPTION_USE_FILE_BUFFER Option value: Boolean This option can be enabled to accumulate output during serialization in a temporary file, rather than an in-memory buffer. This reduces the memory used in serializing a large file, but it is slower than the default behavior.
  • Every solid box in this picture represents a way to describe a modeled domain.
  • The HTML exporter even understands generics in models, highlighting things like type parameters
  • When exporting a model as a schema, we would need the qualified name of the package if we were adding an Ecore package annotation.
  • Before the Importer and Exporter hooks, we used to see all types of approaches to, for example, convert a proprietary format to Ecore: menu items, separate application, tool bar buttons, import wizard, …
  • That’s all one needs to know to provide an importer or an exporter. The rest of this section will address the “non-mandatory” framework we’ve created to make it easier to write converters.
  • Ideally, XML references would be based on identifiers, e.g. UUIDs.
  • The Ecore2Ecore mapping editor is much like the XSD2Ecore mapping editor.
  • The Ecore2XML editor is just a standard EMF-generated editor.
  • These steps cab be done in a customized resource factory implementation to set the default load/save options for all resources managed by the factory…
  • Could also be done by a customized editor or programmatically when calling the load()/save() methods.
  • Transcript

    • 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 https://w3-03.ibm.com/legal/ipl/iplsite.nsf/pages/wtts-trademarks+home
    • 2. Part 1: Introduction to the Eclipse Modeling Framework
    • 3. Agenda
      • EMF in a Nutshell
      • EMF Components
      • The Ecore Metamodel
      • Code Generation, Regeneration and Merge
      • The EMF Runtime
      • Recording Changes
      • Validation
      • Summary
    • 4. EMF Demo
      • Quickly generate a working graphical editor to create and manipulate instances of a UML model
    • 5. What is EMF?
      • A modeling & data integration framework
      • Exploits the facilities offered in Eclipse to…
        • Generate code without losing user customizations (merge)
        • Automate important tasks (such as registering the runtime information)
        • Improve extensibility
        • Provide a UI layer
      • What is an EMF “model”?
        • Specification of your application’s data
          • Object attributes
          • Relationships (associations) between objects
          • Operations available on each object
          • Simple constraints (eg. cardinality) on objects and relationships
        • Essentially it represents the class diagram of the application
    • 6. What does EMF Provide?
      • From a model specification, EMF can generate efficient, correct, and easily customizable implementation code
      • Out of the box, EMF provides support for
        • Java ™ interfaces
        • UML
        • XML Schema
      • EMF converts your models to Ecore (EMF metamodel)
      • Tooling support within the Eclipse framework (UI, headless mode, Ant and standalone), including support for generating Eclipse-based and RCP editors
      • Reflective API and dynamic model definition
      • Persistence API with out of box support for XML/XMI (de)serialization of instances of a model
      • And much more….
    • 7. Why EMF?
      • EMF is middle ground in the modeling vs. programming worlds
        • Focus is on class diagram subset of UML modeling (object model)
        • Transforms models into Java code
        • Provides the infrastructure to use models effectively in your application
      • Very low cost of entry
        • EMF is free and open source
        • Full scale graphical modeling tool not required
        • Reuses your knowledge of UML, XML Schema, or Java
      • It’s real, proven technology (since 2002)
    • 8. EMF History
      • First version was released in June, 2002
      • Originally based on MOF (Meta Object Facility)
        • From OMG (Object Management Group)
        • Abstract language and framework for specifying, constructing, and managing technology neutral metamodels
      • EMF evolved based on experience supporting a large set of tools
        • Efficient Java implementation of a practical subset of the MOF API
      • 2003: EMOF defined (Essential MOF)
        • Part of OMG’s MOF 2 specification; UML2 based
        • EMF is approximately the same functionality
          • Significant contributor to the spec; adapting to it
    • 9. Who is Using EMF Today?
      • Eclipse projects
        • Foundation for the Modeling Project: Graphical Modeling Framework (GMF), EMF Ontology Definition Metamodel (EODM), UML2…
        • 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)…
      • Commercial offerings
        • IBM, Borland, Oracle, Omondo, Versata, MetaMatrix, Bosch, Ensemble…
      • Applied sciences
        • Darmstadt University of Technology, Mayo Clinic College of Medicine, European Space Agency…
      • Large open source community
        • Over 1,000,000 download requests in 2006
    • 10. EMF at IBM
      • Pervasive usage across product lines
        • IBM ® Rational ® Software Architect
        • IBM Rational Application Developer for WebSphere Software
        • IBM WebSphere ® Integration Developer
        • IBM WebSphere Application Server
        • IBM Lotus ® Workplace
      • Emerging technology projects: alphaWorks ®
        • Emfatic Language for EMF Development (http://www.alphaworks.ibm.com/tech/emfatic)
        • Model Transformation Framework (http://www.alphaworks.ibm.com/tech/mtf)
        • XML Forms Generator (http://www.alphaworks.ibm.com/tech/xfg)
    • 11. What Have People Said About EMF?
      • 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.
      • – Vlad Varnica, OMONDO Business Development Director, 2002
      • 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].
      • – Jason Bloomberg, Senior analyst for XML & Web services, ZapThink, 2003
      • 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.
      • – Bruch, Bockisch, Schäefer, Mezini, Darmstadt Univ. of Technology, 2005
      • [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 .
      • – David Frankel, as seen in Business Process Trends, March 2005
    • 12. Creating the Ecore Model
      • Representing the modeled domain in Ecore is the first step in using EMF
      • Ecore can be created
        • Directly using the EMF editors
        • Through a graphical UI provided by external contributions
        • By converting a model specification for which a Model Importer is available
      • Model Importers available in EMF
        • Java Interfaces
        • UML models expressed in Rational Rose ® files
        • XML Schema
      • Choose the one matching your perspective or skills
    • 13. Model Importers Available in EMF
      • Java Interfaces
      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. Model Importers Available in EMF
      • UML Class Diagram
    • 15. Model Importers Available in EMF
      • XML Schema
      <?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?> <xsd:schema xmlns:xsd=&quot;http://www.w3.org/2001/XMLSchema&quot; targetNamespace=&quot;http://www.example.com/SimplePO&quot; xmlns:PO=&quot;http://www.example.com/SimplePO&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. Unifying Java, XML and UML Technologies
      • The Model Importers available in EMF were carefully chosen to integrate today’s most important technologies
      • All three forms provide the same information
        • Different visualization/representation
        • The application’s “model” of the structure
      • From a model definition, EMF can generate
        • Java implementation code, including UI
        • XML Schemas
        • Eclipse projects and plug-in
    • 17. Typical EMF Usage Scenario
      • Create an Ecore model that represents the domain you are working on
        • Import UML (e.g. Rose .mdl file)
        • Import XML Schema
        • Import annotated Java interfaces
        • Create Ecore model directly using EMF's Ecore editor or a graphical editor
      • Generate Java code for model
      • Prime the model with instance data using generated EMF model editor
      • Iteratively refine model (and regenerate code) and develop Java application
        • You will use the EMF generated code to implement the use cases of your application
      • Optionally, use EMF.Edit to build customized user interface
    • 18. EMF and Java 5.0
      • EMF 2.3 exploits the capabilities of Java 5.0
        • Generics
        • Typesafe enums
        • Annotations
        • Enhanced for loop
        • Autoboxing
      • EMF 2.3 provides a 5.0-targeted runtime that can only be run on a Java 5.0 or later VM
      • The code generator can also produce application code that runs on a 1.4 VM against the EMF 2.2.x runtime
      • This is a recognition that Java 5.0 is the way forward, but the transition need not be painful for the user
    • 19. EMF and Java 5.0
      • Want to know more about Java 5.0 and EMF?
      • Modeling Generics with Ecore
      • Tuesday, 11:10 am
      • Grand Ballroom D
      • Java 5: A Developer’s Experience
      • Thursday, 10:10 am
      • Room 203-204
    • 20. Agenda
      • EMF in a Nutshell
      • EMF Components
      • The Ecore Metamodel
      • Code Generation, Regeneration and Merge
      • The EMF Runtime
      • Recording Changes
      • Validation
      • Summary
    • 21. EMF Architecture EMF Runtime EMF Tools Core Edit Codegen Model Editor Application Generates Eclipse Platform
    • 22. EMF Components
      • EMF Core
        • Ecore metamodel
        • Model change notification & validation
        • Persistence and serialization
        • Reflection API
        • Runtime support for generated models
      • EMF Edit
        • Helps integrate models with a rich user interface
        • Used to build editors and viewers for your model
        • Includes default reflective model editor
      • EMF Codegen
        • Code generator for core and edit based components
        • Extensible model importer/exporter framework
    • 23. EMF Tools: Model Import and Generation
      • Generator Features:
      • Customizable JSP-like templates (JET)
      • JDT-integrated, command-line, or Ant
      • Fully supports regeneration and merge
      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. EMF Model Importers
      • UML
        • Rational Rose .mdl file
        • Eclipse UML2 project provides importer for .uml2
      • Annotated Java
        • Java interfaces representing modeled classes
        • Javadoc annotations using @model tags to express model properties not captured by method declarations
        • Lowest cost approach
      • XML Schema
        • Describes the data of the modeled domain
        • Provides richer description of the data, which EMF exploits
      • Ecore model (*.ecore file)
        • Just creates the generator model (discussed later)
        • Also handles EMOF (*.emof)
    • 25. Ecore Model Creation
      • An Ecore model is created within an Eclipse project via a wizard
      • Input: one of the model specifications from the previous slide
      • Output:
        • modelname.ecore
          • Ecore model file in XMI format
          • Canonical form of the model
        • modelname.genmodel
          • A “generator model” for specifying generator options
          • Contains decorators for Ecore model elements, providing details that would otherwise pollute the model (e.g. target directories for code generation)
          • EMF code generator is an EMF .genmodel editor
          • Automatically kept in synch with .ecore file
    • 26. Ecore Model Editor
      • A generated (and customized) EMF editor for the Ecore model
      • Create, delete, etc. model elements (EClass, EAttribute, EReference, etc.) using pop-up actions in the editor's tree
      • Set names, etc. in the Properties view
    • 27. Ecore Model Editor
      • A graphical editor is a better approach
        • GMF Ecore Diagram Example (http://www.eclipse.org/gmf/)
        • Omondo EclipseUML (http://www.omondo.com/)
    • 28. EMF Generator
      • Similar layout to Ecore model editor
      • Automatically keeps in synch with .ecore changes
      • Generate code with pop-up menu actions
        • Generate Model Code
        • Generate Edit Code
        • Generate Editor Code
        • Generate Test Code
        • Generate All
      • Code generation options in Properties view
      • Generator > Reload to reload .genmodel and .ecore files from original model form
    • 29. Agenda
      • EMF in a Nutshell
      • EMF Components
      • The Ecore Metamodel
      • Code Generation, Regeneration and Merge
      • The EMF Runtime
      • Recording Changes
      • Validation
      • Summary
    • 30. The Ecore (Meta) Model
      • Ecore is EMF's model of a model
        • Also called a “metamodel”
        • Persistent representation is XMI
    • 31. The Ecore Metamodel
    • 32. Partial List of Ecore Data Types
      • Ecore data types are serializable and custom data types are supported
      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. Ecore Model for Purchase Orders is represented in Ecore as
    • 34. Purchase Order Ecore XMI
      • Alternate serialization format is EMOF (Essential MOF) XMI
        • Part of OMG Meta Object Facility (MOF) 2.0 standard (http://www.omg.org/docs/ptc/04-10-15.pdf)
      <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. Agenda
      • EMF in a Nutshell
      • EMF Components
      • The Ecore Metamodel
      • Code Generation, Regeneration and Merge
      • The EMF Runtime
      • Recording Changes
      • Validation
      • Summary
    • 36. Code Generation
      • EMF framework is lightweight
        • Generated code is clean, simple, efficient
      • EMF can generate
        • Model implementation
        • UI-independent edit support
        • Editor and views for Eclipse IDE-integrated or RCP application
        • JUnit test skeletons
        • Manifests, plug-in classes, properties, icons, etc.
    • 37. Generated Model Code
      • Interface and implementation for each modeled class
        • Includes get/set accessors for attributes and references
        • Usage example
      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. Generated Model Code
      • Factory to create instances of model objects
      • Package class provides access to metadata
      • Also generated: switch utility, adapter factory base, validator, custom resource, XML processor
      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. Generated Edit/Editor Code
      • Viewing/editing code divided into two parts
        • UI-independent code
          • Item providers (adapters)
          • Item provider adapter factory
        • UI-dependent code
          • Model creation wizard
          • Editor
          • Action bar contributor
          • Advisor (RCP)
        • By default each part is placed in a separate Eclipse plug-in
    • 40. Java 5.0 Constructs
      • For a new model, EMF 2.3 targets the compiler compliance level specified by the containing project (or the workspace default)
      • To generate code with Java 5.0 constructs for an existing model, use the “Compliance Level” property on the GenModel
    • 41. Summary of Generated Artifacts
      • Model
        • Interfaces and classes
        • Type-safe enumerations
        • Package (metadata)
        • Factory
        • Switch utility
        • Adapter factory base
        • Validator
        • Custom resource
        • XML Processor
      • Edit (UI independent)
        • Item providers
        • Item provider adapter factory
      • Editor
        • Model Wizard
        • Editor
        • Action bar contributor
        • Advisor (RCP)
      • Tests
        • Test cases
        • Test suite
        • Stand-alone example
      • Manifests, plug-in classes, properties, icons...
    • 42. Regeneration and Merge
      • Hand-written code can be added to generated code and preserved during regeneration
        • This merge capability has an Eclipse dependency, so is not available standalone
      • All generated classes, interfaces, methods and fields include @generated marker in their Javadoc
      • To replace generated code:
        • Remove @generated marker
        • Or include additional text, e.g.
          • @generated NOT
      • Methods without @generated marker are left alone during regeneration
    • 43. Regeneration and Merge
      • Extend (vs. replace) generated method through redirection
        • Append “Gen” suffix to the generated method's name
      /** * <!-- 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. The Code Generation Process Java Code Model Importer JET Simplified version UML Java Model ? XML Schema GenModel Ecore
    • 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. Agenda
      • EMF in a Nutshell
      • EMF Components
      • The Ecore Metamodel
      • Code Generation, Regeneration and Merge
      • The EMF Runtime
      • Recording Changes
      • Validation
      • Summary
    • 47. EMF Runtime
      • Persistence and serialization of model data
        • Proxy resolution and demand load
      • Automatic notification of model changes
      • Bi-directional reference handshaking
      • Dynamic object access through a reflective API
      • Runtime environments
        • Eclipse
          • Full IDE
          • RCP
        • Standalone Java
    • 48. Persistence and Serialization
      • Serialized data is referred to as a resource
      • Data can be spread out among a number of resources in a resource set
      • One resource is loaded at a time, even if it has references to objects in other resources in the resource set
        • Proxies exist for objects in other resources
        • Lazy or demand loading of other resources as needed
        • A resource can be unloaded
    • 49. Resource Set
      • Context for multiple resources that may have references among them
      • Usually just an instance of ResourceSetImpl, or a customized subclass
      • Provides factory method for creating new resources in the set:
      • Also provides access to the registries, URI converter, and default load options for the set
      ResourceSet rs = new ResourceSetImpl (); URI uri = URI.createFileURI(&quot;C:/data/po.xml&quot;); Resource resource = rs. createResource (uri);
    • 50. Resource Factory Registry
      • Returns a resource factory for a given type of resource
        • Based on the URI scheme or filename extension
        • Determines the type of resource, hence format for save/load
      • For models created from XML Schema, the generated custom resource factory implementation should be registered to ensure schema-conformant serialization
        • When running as a plug-in under Eclipse, EMF provides an extension point for registering resource factories
        • Generated plugin.xml registers generated resource factory against a package specific extension (e.g. “po”)
      • Global registry: Resource.Factory.Registry.INSTANCE
        • Consulted if no registered resource factory found locally
      Resource.Factory.Registry reg = rs. getResourceFactoryRegistry (); reg. getExtensionToFactoryMap ().put(&quot; xml &quot;, new XMLResourceFactoryImpl ());
    • 51. Package Registry
      • Returns the package identified by a given namespace URI
        • Used during loading to access the factory for creating instances
      • Global registry: EPackage.Registry.INSTANCE
        • Consulted if no registered package found locally
      • Running in Eclipse, EMF provides an extension point for globally registering generated packages
      • Even standalone, a package automatically registers itself when accessed:
      EPackage.Registry registry = rs. getPackageRegistry (); registry.put( POPackage.eNS_URI , POPackage.eINSTANCE ); POPackage poPackage = POPackage.eINSTANCE;
    • 52. Resource
      • Container for objects that are to be persisted together
        • Convert to and from persistent form via save() and load()
        • Access contents of resource via getContents()
      • EMF provides XMLResource implementation
      • Other, customized XML resource implementations, provided, too (e.g. XMI, Ecore, EMOF)
      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. 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. Model Change Notification
      • Every EMF object is also a Notifier
        • Send notification whenever an attribute or reference is changed
        • EMF objects can be “observed” in order to update views and dependent objects
      Adapter poObserver = ... purchaseOrder. eAdapters ().add(poObserver);
    • 55. Model Change Notification
      • Observers or listeners in EMF are called adapters
        • An adapter can also extend class behavior without subclassing
        • For this reason they are typically added using an AdapterFactory
      PurchaseOrder purchaseOrder = ... AdapterFactory somePOAdapterFactory = ... Object poExtensionType = ... if (somePOAdapterFactory. isFactoryForType (poExtensiontype)) { Adapter poAdapter = somePOAdapterFactory. adapt (purchaseOrder, poExtensionType); ... }
    • 56. Model Change Notification
      • Efficient notification in “set” methods
        • Checks for listeners before creating and sending notification
      public String getShipTo() { return shipTo; } public void setShipTo(String newShipTo) { String oldShipTo = shipTo; shipTo = newShipTo; if (eNotificationRequired()) eNotify(new ENotificationImpl(this, ... ); }
    • 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. Bidirectional Reference Handshaking p1. setNext (p3); p2 p1 p2 p3 previous next next previous next previous next previous change notification
    • 59. Bidirectional Reference Handshaking
      • This multi-step procedure is implemented using InternalEObject methods:
        • eInverseRemove()
        • eInverseAdd()
      • Framework list implementations and generated setters directly invoke them on target objects as needed
      • Notifications are accumulated using a NotificationChain and fired off at the end
        • They are not used to implement the handshaking
    • 60. Reflection
      • All EMF classes implement interface EObject
      • Provides an efficient API for manipulating objects reflectively
        • Used by the framework (e.g., serialization/deserialization, copy utility, generic editing commands, etc.)
        • Also key to integrating tools and applications built using EMF
      public interface EObject { EClass eClass (); Object eGet (EStructuralFeature sf); void eSet (EStructuralFeature sf, Object val); ... }
    • 61. Reflection Example
      • Setting an attribute using generated API:
      • Using reflective API:
      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. Reflective Performance
      • Efficient generated switch-based implementation of reflective methods
      public Object eGet (int featureID, ...) { switch (featureID) { case POPackage.PURCHASE_ORDER__SHIP_TO: return getShipTo (); case POPackage.PURCHASE_ORDER__BILL_TO: return getBillTo (); ... } }
    • 63. Reflection Benefits
      • Reflection allows generic access to any EMF model
        • Similar to Java’s introspection capability
        • Every EObject (that is, every EMF object) implements the reflection API
      • An integrator need only know your model!
      • A generic EMF model editor uses the reflection API
        • Can be used to edit any EMF model
    • 64. Dynamic EMF
      • Ecore models can be defined dynamically in memory
        • No generated code required
        • Dynamic implementation of reflective EObject API provides same runtime behavior as generated code
        • Also supports dynamic subclasses of generated classes
      • All EMF model instances, whether generated or dynamic, are treated the same by the framework
      • A dynamic Ecore model can be defined by
        • Instantiating model elements with the Ecore API
        • Loading from a .ecore file
    • 65. Dynamic EMF Example
      • Model definition using the Ecore API
      EPackage poPackage = EcoreFactory.eINSTANCE. createEPackage (); poPackage. setName (&quot;po&quot;); poPackage. setNsURI (&quot;http://www.example.com/PurchaseOrder&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. XML Processor
      • Simplified API for loading and saving XML
        • Handles resource set, registries, etc. under the covers
      • Can automatically create a dynamic Ecore representation of a schema
        • Load/save instance documents without generating code
        • Manipulate the objects using reflective EObject API
      URI schemaURI = ... String instanceFileName = ... XMLProcessor processor = new XMLProcessor (schemaURI); Resource resource = processor. load (instanceFileName, null); EObject documentRoot = resource.getContents.get(0);
    • 67. Agenda
      • EMF in a Nutshell
      • EMF Components
      • The Ecore Metamodel
      • Code Generation, Regeneration and Merge
      • The EMF Runtime
      • Recording Changes
      • Validation
      • Summary
    • 68. Recording Changes
      • EMF provides facilities for recording the changes made to instances of an Ecore model
      • Change Model
        • An EMF model for representing changes to objects
        • Directly references affected objects
        • Includes “apply changes” capability
      • Change Recorder
        • EMF adapter
        • Monitors objects to produce a change description (an instance of the change model)
    • 69. Change Model
    • 70. Change Recorder
      • Can be attached to EObjects, Resources, and ResourceSets
        • Monitors changes to the objects and their contents trees
      • Produces a description of the changes needed to return to the original state (a reverse delta)
      • Result: a change description with one change, setting billTo to “123 Elm St.”
      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. Applying Changes
      • Given a change description, the change can be applied:
        • ChangeDescription.apply()
          • consumes the changes, leaving the description empty
        • ChangeDescription.applyAndReverse()
          • reverses the changes, leaving a description of the changes originally made (the forward delta)
      • The model is always left in an appropriate state for applying the resulting change description
    • 72. Example: Transaction Capability
      • If any part of the transaction fails, undo the changes
      ChangeRecorder changeRecorder = new ChangeRecorder(resourceSet); try { // modifications within resource set } catch (Exception e) { changeRecorder. endRecording (). apply (); }
    • 73. Agenda
      • EMF in a Nutshell
      • EMF Components
      • The Ecore Metamodel
      • Code Generation, Regeneration and Merge
      • The EMF Runtime
      • Recording Changes
      • Validation
      • Summary
    • 74. Validation Framework
      • Model objects validated by external EValidator
      • Detailed results accumulated as Diagnostics
        • Essentially a non-Eclipse equivalent to IStatus
        • Records severity, source plug-in ID, status code, message, other arbitrary data, and nested children
      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. Invariants and Constraints
      • Invariant
        • Defined directly on the class, as an operation with <<inv>> stereotype
        • Stronger statement about validity than a constraint
      • Constraint
        • Externally defined for the class via a method on the validator
    • 76. Generated EValidator Implementations
      • Generated for each package that defines invariants or constraints
      • Dispatches validation to type-specific methods
      • For classes, a validate method is called for each invariant and constraint
        • Method body must be hand coded for invariants and named constraints
    • 77. Schema-Based Constraints
      • In XML Schema, named constraints are defined via annotations:
      • Also, constraints can be defined as facets on simple types, and no additional coding is required
        • Constraint method implementation generated
      <xsd:annotation> <xsd:appinfo source=&quot;http://www.eclipse.org/emf/2002/Ecore&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. Framework EValidator Implementations
      • EObjectValidator validates basic EObject constraints:
        • Multiplicities are respected
        • Proxies resolve
        • All referenced objects are contained in a resource
        • Data type values are valid
      • Used as base of generated validators and directly for packages without additional constraints defined
    • 79. Framework EValidator Implementations
      • Diagnostician walks a containment tree of model objects, dispatching to package-specific validators
        • Diagnostician.validate() is the usual entry point
        • Obtains validators from its EValidator.Registry
      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. Agenda
      • EMF in a Nutshell
      • EMF Components
      • The Ecore Metamodel
      • Code Generation, Regeneration and Merge
      • The EMF Runtime
      • Recording Changes
      • Validation
      • Summary
    • 81. Summary
      • EMF is low-cost modeling for the Java mainstream
      • Boosts productivity and facilitates integration
      • Mixes modeling with programming to maximize the effectiveness of both
    • 82. Summary
      • EMF provides…
        • A metamodel (Ecore) with which your domain model can be specified
          • Your model can be created from UML, XML Schema or annotated Java interfaces
        • Generated Java code
          • Efficient and straightforward
          • Code customization preserved
        • Persistence and Serialization
          • Resource-based serialization
          • Proxy resolution and demand loading
          • Default resource implementation is XMI (XML metadata interchange), but can be overridden
    • 83. Summary
      • EMF provides…
        • Model change notification is built in
          • Just add adapters (observers) where needed
        • Reflection and dynamic EMF
          • Full introspection capability
        • Simple change recording and roll-back
        • Extensible validation framework
        • Standalone runtime support
        • A UI-independent layer for viewing and editing modeled data (EMF.Edit)
    • 84. Part 2: Advanced Features of the Eclipse Modeling Framework
    • 85. Agenda
      • Working with Resources and ResourceSets
      • Customizing the Code Generator
      • Tuning for Performance and/or Memory Footprint
      • Importers and Exporters
      • Supporting Backward and Forward Compatibility
      • Summary
    • 86. Working with Resources and ResourceSets
      • Working with proxies
        • Identifying proxies
        • Using the Validation Framework to detect unresolved proxies
        • Using “fragment queries” to handle unresolved proxies
      • Cross-Resource Containment
      • Inverse References
      • Resource Tips & Tricks
        • Unloading
        • Tracking modification
        • Am I loading something?
    • 87. Persistence and Serialization Review
      • Serialized data is referred to as a resource
      • Data can be spread out among a number of resources in a resource set
      • One resource is loaded at a time, even if it has references to objects in other resources in the resource set
        • Proxies exist for objects in other resources
        • Lazy or demand loading of other resources as needed
        • A resource can be unloaded
    • 88. Identifying Proxies
      • In some scenarios it may be important to know up-front what are the proxies referenced by a given object
        • Check whether the user has everything that will be necessary to load the model
        • Extract missing resources from the repository
        • Decide whether loading a specific object is a long or short operation
      • org.eclipse.emf.ecore.util.EcoreUtil.ProxyCrossReferencer
        • A CrossReferencer that finds proxies without resolving them
        • For each object in a given context (resource, resource set, EObject, collection), checks if the referenced objects are in the same resource or not
    • 89. Going Deeper: EcoreUtil’s CrossReferencers
      • Utility classes that find “uses” of an object
      • Also the data structures that hold the objects they find
        • A CrossReferecer is a java.util.Map
        • On each Map.Entry
          • Key: reference target
          • Value: list of EStructuralFeature.Setting with all the source object-feature pairs referencing the keyed target
    • 90. Going Deeper: EStructuralFeature.Setting
      • Interface that represents the value held by a feature of an EObject
      • Exposes all the feature-related methods of EObject
        • eGet, eSet, eIsSet, and eUnset
    • 91. Going Deeper: Types of Reference
      • Containment Reference
        • Has an “implicit” opposite (eObject.eContainer())
      • Container Reference
        • An explicit reference defined as the opposite of a containment reference
      • Cross-Reference
        • May or may not have an opposite
      • Any reference can refer to an EObject located in either the same or different resource
    • 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. Validating Proxies
      • The validation framework can be used to validate proxies
      • The EObjectValidator checks if all the referenced objects of a given EObject are resolved
        • The proxy references are resolved during the validation
      • If a proxy is broken, the validation produces a Diagnostic with EObjectValidator. EOBJECT__EVERY_PROXY_RESOLVES as its error code
    • 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. Handling Broken Proxies
      • Your application can provide a mechanism to handle broken proxies by
        • Reporting the error to the user
        • Avoiding use of the object(s) that could not be resolved
        • Recovering the missing object(s)
      • EMF doesn’t provide such a mechanism but provides hooks to help you implement one
        • Fragment query capability is one of these hooks
    • 96. Stepping Back: Uniform Resource Identifier (URI)
      • A formatted string that serves as an identifier for a resource
      • Specification:
        • Definition: http://www.ietf.org/rfc/rfc1630.txt
        • Generic Syntax: http://www.ietf.org/rfc/rfc2396.txt
      • Syntax:
        • Generic
        • [ scheme : ] scheme-specific-part [ # fragment ]
        • Hierarchical
          • [ scheme : ][ // authority ][ path ][ ? query ][ # fragment ]
      • Used in EMF to identify a resource, an object in a resource, or an Ecore package (namespace URI)
    • 97. Fragment Queries
      • The idea is to “decorate” the fragment portion of a URI with details that further describe the referenced object
        • The description can be used by a service to locate the object or to enrich an error message to be presented to the user
      • Query data
        • Added to the fragment portion of the object’s URI
        • Must be at the end of the URI fragment portion
        • Is delimited by “?”
        • Example: file:/c:/dir/library.xmi #//@books.0?Book.ISBN.0131425420?
      Fragment Query URI Fragment
    • 98. Saving Fragment Queries
      • If you are using a XMLResource to serialize your objects
        • 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
        • Override the createXMLHelper() method of org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl to return an instance of your XMLHelper
      • The getURIFragmentQuery(…) method returns the string that is used as the “query”
        • The string should not contain the delimiter character ( ? )
        • A null string indicates that there is no query
        • The characters must be valid URI fragment characters (as defined by the specification)
    • 99. Going Deeper: org.eclipse.emf.ecore.xmi.XMLHelper
      • Interface used by the default resource implementations
        • Not used by clients
      • Single place where the methods used to save and load objects are located
        • Simplifies customizations
    • 100. Using Fragment Queries
      • EMF doesn’t enforce the use of fragment queries
      • Reasonable approach:
        • Load an object
        • Try to resolve its proxies
        • Identify the remaining (broken) proxies
        • Use the fragment query of the broken proxies to either report the problem to the user or recover the missing objects
    • 101. Cross-Resource Containment
      • Allows an object hierarchy to be persisted across multiple resources
        • eObject.eResource() may be different from eObject.eContainer().eResource()
      • Must be explicitly enabled
        • The containment reference has to be set to resolve proxies
        • Also, on generated models, the value of the “Containment Proxies” generator model property has to be set to ‘true’
    • 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. 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. EcoreUtil Methods for Cross-Resource Containment
      • 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
      • The *Proper* methods available in EcoreUtil only deal with the “local” children of a containment tree
      All children Local children
    • 105. Inverse References
      • Sometimes it may be handy to retrieve the opposite of a unidirectional association end
        • For example, the use case you are implementing requires a navigation that was not anticipated when the model was defined
      • EMF provides two mechanisms
        • CrossReferencer
        • ECrossReferenceAdapter
    • 106. Going Deeper: Associations and References
      • An association between two classes allows their instances to “communicate” with each other
      • Each navigable end of an association is represented by an EReference in Ecore
        • If the association is bidirectional, it will be represented by two references, r1 and r2 where r1.getEOpposite() == r2 && r2.getEOpposite() == r1
      Associations References
    • 107. Using a CrossReferencer
      • Dynamically computes a map with the target object and the list of settings that “refer” to it
        • This computation may be a long operation depending on the number of objects
      • The map represents a snapshot of the state of the objects
        • As the objects change, the settings’ values may become inconsistent with the map
      • Requires a context to compute the map
        • The context can be a collection of EObjects, a resource, or a resource set, or a combination of these
        • Objects that are not in the scope of the context won’t be available in the map
    • 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. Using the ECrossReferenceAdapter
      • A special adapter that
        • Attaches itself to all objects in a containment hierarchy
          • May pose a memory footprint problem depending on the number of objects
        • Keeps a CrossReferencer in sync with the state of the objects
      • The application can determine and change the context used when computing the map
    • 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. Resource Tips & Tricks
      • Unloading a resource
        • Resource.unload()
        • EMF’s default implementation performs the following steps:
          • Sets the loaded attribute to false;
          • Caches an iterator with all the proper contents of all objects held by the resource
          • Clears the resource’s content, error and warning lists
          • Turns each object returned by the iterator into a proxy and clears its adapter list
          • Fires a notification
            • Feature ID = Resource. RESOURCE__IS_LOADED
        • You may also remove the resource from the resource set
    • 112. Resource Tips & Tricks
      • Tracking modification
        • Resource.setTrackingModification(boolean)
        • When activated, EMF’s default implementation performs the following steps:
          • Instantiates an Adapter and registers it on all proper objects
            • The adapter calls Resource.setModified(boolean) after receiving a notification
          • Registers the adapter on any object added to the resource and deregisters it from objects that are removed
        • When deactivated, the default implementation removes the adapter from the objects
        • You can manually define what is the isModified state of a resource
    • 113. Resource Tips & Tricks
      • Am I loading something?
        • Resource.Internal.isLoading()
          • Every Resource is supposed to implement the Resource.Internal interface
        • When a resource is being loaded the isLoading() method returns true
    • 114. Agenda
      • Working with Resources and ResourceSets
      • Customizing the Code Generator
      • Tuning for Performance and/or Memory Footprint
      • Importers and Exporters
      • Supporting Backward and Forward Compatibility
      • Summary
    • 115. Generating Customized Code
      • The EMF code generator can be customized in various ways to meet the needs of your application
      • There are different levels of customization
        • Generator Options
        • Dynamic Templates
        • Generator Extension
    • 116. Generator Options
      • 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
        • Suppress Interfaces
        • Suppress EMF Metadata
        • Root Extends Interface
        • Suppress EMF Types
        • Suppress EMF Model Tags
    • 117. Generator Options
      • All can be adjusted as properties of the GenModel element, the root object in the generator
    • 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. Suppress Interfaces
      • Improves performance since dispatch through an interface is slower and less likely to be in-lined by a JIT compiler
      • Reduces byte code footprint somewhat
      • Can only be used for models with no multiple inheritance
    • 120. Suppress EMF Metadata
      • Helps produce an API with no visible EMF dependencies, i.e. a &quot;pure&quot; API
      /** * 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. Root Extends Interface
      • Helps produce an API with no visible dependencies on EMF, or an API that visibly participates in another framework
      • ‘ Root Extends Class’ and ‘Root Implements Interface’ are also available (classes must implement InternalEObject)
      /** * 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. Suppress EMF Model Tags
      • Helps produce an API with no visible dependencies on EMF
      /** * 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. Suppress EMF Types
      • EList, EMap, and EObject suppressed
      • Applies to feature, operation and parameter types
      • Helps produce an API with no visible dependencies on EMF
      /** * 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. Dynamic Templates
      • The content of the templates used by the EMF code generator can be changed or replaced by enabling dynamic templates
      • Set the value of the ‘Dynamic Templates’ generator model property to ‘true’
      • Set the value of the ‘Template Directory’ generator model property to the location of the custom templates
      • Dynamic templates can be customized in three ways
        • Replacement
        • Insertions
        • Overrides
    • 125. Template Replacement
      • Copy default template to the dynamic template directory (with the same name and relative location) and modify as desired
      • Modified template is compiled dynamically and used in place of the default template
      • Must keep in sync with changes in default templates (“clone and own”)…
    • 126. Template Insertions
      • Can insert content into default templates via insertion points identified using JET @include directive (fail=“silent”)
      • Dynamic template includes default template; insertions are included and compiled dynamically, result is used in place of the default template
      • By convention, insertions are placed in a folder named after the including template and end with a .insert.*jet extension
      • A number of insertion points have been defined for some commonly customized EMF templates (i.e. Class.javajet, ItemProvider.javajet, TestCase.javajet)
    • 127. Template Overrides
      • Can override content of default templates via override points identified using JET @include directive (fail=“alternative”)
      • Dynamic template includes default template; overrides are included and compiled dynamically, result is used in place of the default template
      • By convention, overrides are placed in a folder named after the including template and end with a .override.*jet extension
      • A number of override points have been defined for some commonly customized EMF templates (i.e. Class.javajet, ResourceFactoryClass.javajet, TestCase.javajet)
    • 128. Template Insertions and Overrides
      • Simplified example from Class.javajet:
      <%@ 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. Generator Extension
      • EMF’s generator is extensible
        • Code generation is performed by visiting the elements in the model and invoking templates to generate artifacts for each element
        • Control over this process is delegated to GeneratorAdapters via one or more GeneratorAdapterFactory
        • Additional adapter factories can be plugged into the generator to create adapters that generate additional artifacts
    • 130. Generator Extension
      • Contributing adapters via an extension point:
      • Adapters can be added directly, or via an adapter factory
      • A generic adapter factory is instantiated for each adapter added directly, so it’s more efficient to add multiple adapters via a factory
      <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. Generator Model Extension
      • It is possible, but not advised, to extend the generator model by subclassing its elements
        • New attributes can be added to support additional code generation options
        • 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
        • Protected members of GenModel elements are not considered API: you may have to adapt to changes in the base implementation!
      • A better way to introduce new code generation options is using generator annotations
    • 132. Going Deeper: GenAnnotations
      • GenAnnotations can be added to any instance of GenBase, i.e. any object in a GenModel containment tree (including GenAnnotations themselves)
        • GenBase provides two methods to work with GenAnnotations
          • getGenAnnotations()
          • getGenAnnotation(String source)
      • A GenAnnotation, like its close relative EAnnotation, defines
        • A source attribute, which is typically used to store a URI representing the type of the annotation
        • A details map attribute to store name-value pairs
        • Containment and non-containment references to EObjects
    • 133. Going Deeper: GenAnnotations
      • The GenAnnotations are usually hidden in the Generator
        • You can unhide them by checking &quot;Show Annotations&quot; in the &quot;Generator&quot; menu
    • 134. Agenda
      • Working with Resources and ResourceSets
      • Customizing the Code Generator
      • Tuning for Performance and/or Memory Footprint
      • Importers and Exporters
      • Supporting Backward and Forward Compatibility
      • Summary
    • 135. Performance/Memory Overhead
      • EMF provides a number of mechanisms that can be used to tune the performance and/or memory overhead of your model implementation
      • Code Generator Options
        • Boolean Flags
        • Virtual Feature Delegation
        • Minimal Reflective Methods
      • XMLResource Options
    • 136. Boolean Flags
      • 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
      • Set the value of the ‘Boolean Flags Field’ generator model property to the name of the bit field(s) to be generated or reused
      • 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)
      • Helps reduce memory overhead for models with a large number of Boolean attributes or unsettable features
    • 137. Virtual Feature Delegation
      • 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
      • Set the value of the ‘Feature Delegation’ generator model property to ‘Virtual’
      • Helps reduce memory overhead for models with a large number of features that are often “sparsely” used
    • 138. Minimal Reflective Methods
      • Generates reflective methods that delegate to super , i.e. they delegate switching for any non-matching features to the superclass implementation for dispatching
      • Set the value of the ‘Minimal Reflective Methods’ generator model property to ‘true’ (default)
      • Helps reduce memory (byte code) overhead for models with a large number of inherited features
      • May increase performance overhead for models with deep class hierarchies
    • 139. XMLResource Options
      • XMLResource offers a set of options that can be used to tweak load and save behavior
      • The options are passed to the resource’s save and load methods as entries in a map
        • The key is the constant that represents the option
        • Each option requires an appropriate value
    • 140. XMLResource Load Options
      • OPTION_DEFER_IDREF_RESOLUTION
        • Option value: Boolean
        • Defers resolving references within a resource until the whole document has been parsed
      • OPTION_USE_PARSER_POOL
        • Option value: org.eclipse.emf.ecore.xmi.XMLParserPool
        • Provides a parser pool, from which SAXParser instances are created and reused
      • OPTION_USE_XML_NAME_TO_FEATURE_MAP
        • Option value: java.util.Map
        • 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
    • 141. XMLResource Load Options
      • OPTION_USE_CACHED_LOOKUP_TABLE
        • Option value: java.util.List
        • Specifies a list as a place holder for caching information during the subsequent saving of XML documents
      • OPTION_USE_DEPRECATED_METHODS
        • Option value: Boolean
        • Use methods that were deprecated in EMF
        • The default value is Boolean.TRUE
    • 142. XMLResource Save Options
      • OPTION_FLUSH_THRESHOLD
        • Option value: Integer
        • Specifies a maximum number of characters to allow in the output stream before flushing it
      • OPTION_USE_CACHED_LOOKUP_TABLE
        • Option value: java.util.List
        • Provides a placeholder to cache information about structure of the model (using qualified XML names as a key for caching information)
      • OPTION_CONFIGURATION_CACHE
        • Option value: Boolean
        • Enables caching and reusing generic data in repeated save operations, avoiding the cost of reinitializing the data
    • 143. XMLResource Save Options
      • OPTION_FORMATTED
        • Option value: Boolean
        • Disables formatting of documents, omitting whitespaces and line brakes, to improve the performance of saving and, subsequently, loading the resulting document
      • OPTION_USE_FILE_BUFFER
        • Option value: Boolean
        • Enables accumulating output during serialization in a temporary file, rather than an in-memory buffer
    • 144. Agenda
      • Working with Resources and ResourceSets
      • Customizing the Code Generator
      • Tuning for Performance and/or Memory Footprint
      • Importers and Exporters
      • Supporting Backward and Forward Compatibility
      • Summary
    • 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. Model Importers
      • A Model Importer (aka an importer) is responsible for creating an Ecore model from the description of a modeled domain
        • Each importer knows how to handle a specific format of description
        • An importer is also expected to create the generator model (.genmodel file) for the Ecore Model (.ecore file)
      • EMF provides importers that handle the following formats
        • Rational Rose models
        • XML Schemas
        • Annotated Java Interfaces
        • Ecore and EMOF files
    • 147. Model Exporters
      • A Model Exporter (aka exporter) is able to read an Ecore model and generate another description of the same modeled domain
        • An exporter typically uses the information described in the Generator Model to accomplish its purposes
      • EMF provides two exporters
        • XML Schema
        • XML Schema for XMI
      • EMF also provides an HTML exporter example, which uses JET to produce a package summary
    • 148. Going Deeper: Why is the Generator Model so important?
      • The generator model acts as a decorator for an Ecore model
        • It provides details that would pollute the model, such as the
          • Qualified name of an EPackage
          • Prefix for package-related class names
          • Actual location of the model, edit, editor, and test source folders
      • 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
        • The Java package of the annotated Java interfaces
        • Referenced XML Schemas that may or may not be already represented by Ecore models
      • The generator model is useful to an exporter because
        • It can be used to persist details about the exported artifact
        • Some details may be important to properly describe the modeled domain
    • 149. Using Importers and Exporters
      • The importers and exporters are presented to the user as pages of a standard EMF wizard
        • The registered importers are presented during the execution of the new EMF model or EMF project wizards
        • The list of exporters is shown when the “Export Model…” action is invoked on a .genmodel file
        • The motivation of this design is to let the importers and exporters decide the input that the user needs to provide
          • Each implementation has total control over the number of pages of the wizard and their content
      • The Rose and XML Schema importers are also available as Eclipse applications and Ant tasks
    • 150. Contributing an Importer via an Extension Point
      • The wizard must be a class that implements EMF’s IModelImporterWizard interface
        • 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
      <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. Contributing an Exporter via an Extension Point
      • The wizard must be a class that implements Eclipse’s IWorkbenchWizard interface
        • 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
      <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. Contributing Importers and Exporters via Global Registries
      • The idea is to add the importer/exporter description to the appropriate list
        • ModelImporterManager.INSTANCE.getModelConverterDescriptors()
        • ModelExporterManager.INSTANCE.getModelConverterDescriptors()
      • The importer and exporter descriptions are quite similar, which led to the creation of a common parent interface
    • 153. Agenda
      • Working with Resources and ResourceSets
      • Customizing the Code Generator
      • Tuning for Performance and/or Memory Footprint
      • Importers and Exporters
      • Supporting Backward and Forward Compatibility
      • Summary
    • 154. Backward/Forward Compatibility
      • 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):
        • Use Ecore2Ecore and Ecore2XML to define a mapping between the different model(s) (versions)
        • Use Ecore2XMLExtendedMetaData with save/load options to handle unrecognized data
        • Use a resource handler to pre/post-process data that cannot be mapped automatically
      • Source and target models must have different namespace URIs and XML references must not be based on feature names
    • 155. Ecore2Ecore Mappings
      • Describe a mapping between two Ecore models
      • Can be created from an Ecore (*.ecore) model via the ‘Map To Ecore…’ context menu item in the Package Explorer or Resource Navigator
      • Typically used as a development-time artifact (only)
      • Can include one-to-one, one-to-many, many-to-one, many-to-many, and one-sided mappings
      • Only one-to-one and one-sided (one-to-none, none-to-one) mappings are useful for data migration
    • 156. Ecore2XML Mappings
      • Describe a mapping between an Ecore model and its XML representation
      • 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
      • Often used as a run-time artifact (in conjunction with Ecore2XMLExtendedMetaData)
      • Can include one-to-one and many-to-one mappings, but only the former are useful for data migration
    • 157. Ecore2XMLExtendedMetaData
      • Can be used with the OPTION_EXTENDED_META_DATA save/load option defined on XMLResource to affect how data are serialized/deserialized
      • Will consult registered Ecore2XML mappings to determine the XML representation of objects
      my.y my.x x_2_y.ecore2xml
    • 158. OPTION_RECORD_UNKNOWN_FEATURE
      • Load option defined on XMLResource
      • Will record data for unrecognized types and features in an extension map (XMLResource#getEObjectToExtensionMap()) on the resource
      • Recorded data will be serialized again when the resource is saved (unless the entries in the map have been cleared)
      my.x my.y y => x
    • 159. Resource Handlers
      • Interface XMLResource.ResourceHandler defines callbacks that can be implemented to do special processing before/after a resource is loaded/saved
      • Used with OPTION_RESOURCE_HANDLER save/load option defined on XMLResource
      • Can support backward compatibility by extracting data from a resource’s extension map after it is loaded
      • Can support forward compatibility by inserting data into a resource’s extension map before it is saved
    • 160. Enabling Data Migration
      • Create a package registry and add entries which map the source namespace URI and target Ecore model location to the target package
      • Create an Ecore2XML registry and add an entry which maps the source namespace URI to the Ecore2XML mapping
      • 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
    • 161. Enabling Data Migration
      • Pass Boolean.TRUE as the value for the XMLResource.OPTION_RECORD_UNKNOWN_FEATURE load option
      • If required, pass an implementation of XMLResource.ResourceHandler as the value for the XMLResource.OPTION_RESOURCE_HANDLER load/save option
    • 162. Agenda
      • Working with Resources and ResourceSets
      • Customizing the Code Generator
      • Tuning for Performance and/or Memory Footprint
      • Importers and Exporters
      • Supporting Backward and Forward Compatibility
      • Summary
    • 163. Summary
      • We have seen examples of how flexible and extensible the Eclipse Modeling Framework is
      • 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
    • 164. Part 3: Eclipse Modeling Framework Technologies – Query, Transaction, Validation
    • 165. Agenda
      • EMFT in a Nutshell
      • Validating Models
      • Querying Models
      • Working with Transactions
      • Working with the Operation History
      • Summary
    • 166. What is EMFT?
      • A collection of components that “add on” to EMF to provide value-added capabilities for rich applications
      • Currently includes:
        • Validation – a flexible framework for contributing 3 rd -party constraints to model validation
        • Query – an SQL-like Java API for querying EMF resources
        • Transaction – a transaction protocol for concurrent access to EMF resources
        • CDO, Teneo – object-relational mappings for persistence of EMF resources in RDBMSes
        • JET Editor – a rich editor for JET templates
    • 167. What was EMFT?
      • Formerly in EMFT:
        • OCL – an implementation of the Object Constraint Language for Ecore and UML metamodels; now a component of MDT
        • EODM – an implementation of the Ontology Definition Metamodel for Ecore; now a component of MDT
        • JET (a.k.a. JET2) – next generation of the Java Emitter Templates; now a component of M2T
      • This tutorial will explore the Validation, Query, and Transaction components with a little OCL added for flavour
    • 168. What does the Validation Framework Provide?
      • Extensibility:
        • Constraint providers contribute constraints from any source they deem fit, including the plugin.xml, constraints embedded in models, or external models
        • Constraint parsers contribute support for constraint specification languages. Out of the box, the framework implements Java and OCL support.
        • Traversal strategies contribute knowledge of the model structure and how to discover its extent to validate it
        • Constraint categories and bindings help to organize constraints and activate them in specific applications
        • Validation listeners are notified whenever validation occurs, to provide an appropriate response from the application
    • 169. What does the Validation Framework Provide?
      • Invocation (Triggers)
        • “Batch” validation: initiated by the user or by the system on some important event, validates all or a selected subset of a model
        • “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
          • Constraints can specify which particular changes trigger them (by feature and event type)
      • Support for OCL constraints
        • EMFT Validation uses the OCL component of the MDT project to provide out-of-box support for specifying constraints using OCL
    • 170. What does the Query Framework Provide?
      • A convenient Java API for querying an EMF-based model
        • The API is designed to look and feel like SQL, with SELECT and UPDATE statements, FROM clauses, etc.
        • Offers a wide array of reusable and recombinable predicate objects for specifying WHERE clause conditions
        • Supports nested and compound queries
        • Easily customizable for special requirements in traversing models, etc.
      • Support for OCL
        • Provides predicate classes that specify WHERE conditions as OCL constraints (with context or, optionally, context-free)
    • 171. What does the Transaction API Provide?
      • A transactional editing environment
        • Safe read and write access to EMF resources from multiple concurrent threads
        • Commit protocol providing mechanisms for ensuring model integrity:
          • Validation of the changes performed during the transaction (constraints) using the Validation Framework
          • Pre-commit listeners proactively performing concomitant changes (triggers) to maintain consistency of dependencies
          • Automatic rollback of changes on failure to validate or complete triggers
          • Supports transaction nesting
    • 172. What does the Transaction API Provide?
      • Read/write transactions
        • Give a thread exclusive access to a ResourceSet for the purpose of modifying its content
        • Ensure that other threads do not observe interim (uncommitted) states of the data (“dirty reads”)
      • Read-only transactions
        • Protect against threads concurrently initializing concrete state of the ResourceSet (such as duplicate resolution of proxies or duplicate initialization of ELists)
        • Can be shared cooperatively by multiple reading threads
    • 173. What does the Transaction API Provide?
      • Change events
        • Commit of a transaction sends a ResourceSetChangeEvent to interested listeners, with a summary of the changes that the transaction performed
        • Changes are sent as a single batch, and only on successful commit, so that UI refreshes etc. don’t get any “noise”
      • Integration with Eclipse Workbench APIs
        • Support for delegating the EMF CommandStack to an IOperationHistory
        • Leverages the IUndoContext to support separate undo/redo “stacks” where independent changes occur in a single ResourceSet
    • 174. Agenda
      • EMFT in a Nutshell
      • Validating Models
      • Querying Models
      • Working with Transactions
      • Working with the Operation History
      • Summary
    • 175. Constraint Providers
      • Constraint providers are of two flavours: static and dynamic
        • Static providers declare their constraints in the plugin.xml of a client plug-in of the constrained model
        • Dynamic providers obtain constraints from an arbitrary source at run-time
      • Both kinds of providers can declare constraint categories and include their constraints in categories defined by any provider
        • Categories are hierarchical namespaces for constraints
        • Constraints are grouped by category in the preference page
    • 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:///www.eclipse.org/Library/1.0.0&quot;/> <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. Dynamic Constraint Provider
      • Registered by name of a class implementing the IModelConstraintProvider interface
      • Indicate the packages for which they supply constraints
        • Biggest difference is the absence of a <constraints> element
      • System can optionally cache the provided constraints
      <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:///www.eclipse.org/Library/1.0.0&quot;/> </constraintProvider> </extension>
    • 178. Dynamic Constraint Provider
      • A dynamic constraint provider implements the IModelConstraintProvider interface
      • A descriptor supplies meta-data about a constraint
      • The validation algorithm is supplied by the constraint object in the validate() method
    • 179. Constraints
      • Descriptor provides:
        • ID and localizable name
        • Evaluation mode
        • Target EClasses
        • Triggering events (live)
        • Severity, error message
        • Categorization
        • Enabled state
      • Much of this information appears in the preference page
      • Users can choose which constraints to activate
    • 180. Evaluation Modes
      • Batch validation is usually explicitly requested by the user, via a menu action or toolbar button
      • Live validation is performed automatically as changes are made to EMF resources
        • Live constraints indicate which specific changes trigger them
      <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. Validation Service
      • Evaluation of constraints is performed via the Validation Service
      • The service provides validators corresponding to the available evaluation modes
      • By default, batch validation includes live constraints, also, for completeness
    • 182. Validation Service
      • To validate one or more elements, in batch mode, simply create a new validator and ask it to validate:
      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. Validation Service
      • Live validation does not validate objects, but rather Notification s indicating changes to objects
      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. Creating Constraints
      • Specifying a constraint doesn’t necessarily require any code
      • Requires the OCL component of the MDT project
      <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 l.name <> self.name) ]]> </constraint>
    • 185. Creating Constraints
      • Sometimes the easiest or best way to formulate a constraint is in Java
      • Java constraints extend the AbstractModelConstraint class
      • The validation context provides the validate() method with information about the validation operation
    • 186. Validation Context
      • Provides the element being validated (the target)
      • Indicates the current evaluation mode (live or batch)
        • In case of live invocation, provides the changed feature and the event type
      • Allows constraints to cache arbitrary data for the duration of the current validation operation
      • Provides convenient methods for reporting results
      • Provides the ID of the constraint that is being invoked
    • 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. Listening for Validation Events
      • Every validation operation executed by the Validation Service generates an event
      • The event indicates the kind of validation performed, on what objects, and what were the results (incl. severity)
      • Listeners registered on the extension point are lazily initialized when their selection criteria are met
      <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. Reporting Problems
      • Problems are reported as IConstraintStatus objects. A status knows:
        • The constraint that was violated
        • The objects that violated it
        • The severity and error message, as usual for an IStatus
      • The marker utility encodes all of this information in a problem marker on the appropriate resource, to show in the Problems view
    • 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. Agenda
      • EMFT in a Nutshell
      • Validating Models
      • Querying Models
      • Working with Transactions
      • Working with the Operation History
      • Summary
    • 192. Query Statements
      • SELECT statements filter the objects provided by a FROM clause according to the conditions specified in the WHERE clause
      • SELECT s are IEObjectSource s, so they can be used in FROM clauses to nest queries
      • UPDATE statements use a SET clause to update the objects provided by the FROM clause (filtered, of course, by the WHERE clause)
    • 193. The FROM Clause
      • Uses EMF’s tree iterators to walk the objects being queried
      • Optionally specifies an EObjectCondition filter
      • Search scope is encapsulated in an IEObjectSource
        • provides objects via an iterator. The FROM descends into the contents of these objects if it is a hierarchical IteratorKind
    • 194. The WHERE Clause
      • The WHERE clause specifies a single filter condition
      • This filter condition can be arbitrarily complex
      • Filters can be combined in innumerable ways using the common boolean operators
      • The IN filter detects whether an object is an element of a supplied set (as in SQL)
    • 195. The WHERE Clause
      • The framework provides a condition on the model type of objects
      • Can also filter for objects that are identical to some target ( EObjectInstanceCondition )
    • 196. The WHERE Clause
      • The framework provides conditions that filter objects based on values of their features
      • In particular, the EObjectReferencerCondition filters for cross-references to a particular object
    • 197. The WHERE Clause: Condition Policies
      • For multi-valued structural features, the ConditionPolicy determines whether a Condition must match all values or just any value
        • Correspond to the relational  (for-all) and  (exists) quantifiers
    • 198. The WHERE Clause: Prune Handlers
      • Just as with EMF’s tree iterators, a query’s iteration over its scope can be pruned
      • Any EObjectCondition can have a PruneHandler that determines whether the search tree can be pruned
        • This allows the query to skip over entire sub-trees when a condition knows that it will never be satisfied for any of the contents of the current object
      • The default prune handler in most cases is NEVER which, as the name implies, never prunes
    • 199. The WHERE Clause: Other Conditions
      • The framework includes a variety of conditions for working with primitive-valued EAttribute s
        • Including strings, booleans, and numbers of all kinds
      • Adapters convert inputs to the required data type
        • Default implementations simply cast, assuming that the values already conform
        • Can be customized to convert values by whatever means is appropriate
    • 200. OCL Conditions
      • OCL can be used to specify WHERE clause conditions
      • Only available when the OCL component of MDT is installed
      • An OCLConstraintCondition specifies a boolean-valued expression (i.e., a constraint) that selects those elements for which the expression is true
      • OCL expressions can be contextful or context-free
    • 201. The UPDATE Statement
      • The UPDATE statement behaves much like a SELECT , except that it passes its result objects through the client-supplied SET clause
      • The result of the UPDATE is the subset of the selected objects for which the SET clause returned true (indicating that they were, in fact, modified)
    • 202. SELECT Query in Action
      • Queries can be used for anything from simple search functions to complex structural analysis
      • They can even be used to implement validation constraints!
      IQueryResult result = new SELECT ( new FROM (res.getContents()), new WHERE (new EObjectAttributeValueCondition ( EXTLibraryPackage.Literals.WRITER__NAME, new StringRegularExpressionValue (&quot;.*Da.*&quot;)))).execute(); for (EObject next : result .getEObjects()) { Writer writer = (Writer) next; System.out.println (“Found “ + writer.getName()); } Found Dave Steinberg Found Christian Damus
    • 203. SELECT Query with OCL Condition
      • Context-free OCL conditions are applied to any element on which they can be parsed
      IQueryResult result = new SELECT( new FROM(res.getContents()), new WHERE(new OCLConstraintCondition ( &quot; self.books->isEmpty() &quot;, null /* no EClass implies context-free */))).execute(); for (EObject next : result.getEObjects()) { String label = ((IItemLabelProvider) adapterFactory.adapt( next, IItemLabelProvider.class)).getText(next); System.out.println (&quot;Found &quot; + label); } Found Library New Library Found Writer Unpublished Author
    • 204. UPDATE Query in Action IQueryResult result = new UPDATE ( new FROM(res.getContents()), new WHERE(new OCLConstraintCondition( &quot;Employee->forAll(e | e.manager <> self)&quot;, EXTLibrary.Literals.EMPLOYEE)), new SET () { public boolean set(EObject eObject) { Employee emp = (Employee) eObject; emp. setSalary (emp.getSalary() * 1.05)); return true ; // updated this one }}).execute(); for (EObject next : result .getEObjects()) { Employee emp = (Employee) next; System.out.println (“Updated “ + emp.getFirstName() + &quot; &quot; + emp.getLastName()); } Updated Ed Merks Updated Dave Steinberg Updated Kenn Hussey Updated Christian Damus
    • 205. Agenda
      • EMFT in a Nutshell
      • Validating Models
      • Querying Models
      • Working with Transactions
      • Working with the Operation History
      • Summary
    • 206. What is a Transaction?
      • A transaction is a discrete unit of work in a resource set
        • This work may be reading and writing the resource set contents or simply reading
      • Transactions provide model integrity guarantees
        • Isolation of concurrent threads to prevent data corruption
        • Validation of changes on commit, rolling back (undoing those changes) automatically when data integrity is violated
        • Automatic execution of triggers on commit, to proactively maintain data integrity
      • This is not a concurrent transactional environment
        • Transactions on multiple threads execute in strictly serial order
    • 207. What is a Transaction?
      • Transactions in a resource set are managed by a TransactionalEditingDomain
        • Read/write transactions are created by execution of commands on the domain’s TransactionalCommandStack
        • Read-only transactions are created by execution of Runnable s via TransactionalEditingDomain::runExclusive()
      • Most clients will never need to interact directly with Transaction objects, but only with the editing domain
    • 208. Creating Transactional Editing Domains
      • Transactional editing domains are created by factories
        • Use the TransactionalEditingDomain.Factory.INSTANCE shared instance to create a private domain for your editor
      • To share one domain instance amongst multiple editors in an application, register a domain ID
        • Add your editing domain instance to the TransactionalEditingDomain.Registry.INSTANCE
        • Or, register it statically on the editingDomains extension point, specifying a factory for the registry to create it on demand
      <extension point=&quot; org.eclipse.emf.transaction.editingDomains &quot;> < domain id =&quot;com.example.MyEditingDomain&quot; factory =&quot;com.example.domain.MyCustomFactory&quot;/> <!– factory is optional; implied default is the shared instance --> </extension>
    • 209. Obtaining the Editing Domain
      • Any editor that needs to access the registered editing domain simply gets it from the registry
        • It is lazily created, using the associated factory, on first access
      static final String DOMAIN_ID = “ com.example.MyEditingDomain ”; public void init(IEditorSite site, IEditorInput input) throws PartInitException { // get our editing domain domain = TransactionalEditingDomain. Registry.INSTANCE .getEditingDomain(DOMAIN_ID); // load our input resource String fileName = ((IFileEditorInput) input).getFile() .getLocation(); resource = domain. loadResource (fileName); }
    • 210. Creating Read/Write Transactions
      • To do work in a read/write transaction, simply execute a Command on the TransactionalCommandStack
        • Just like using a regular EMF Editing Domain
      • If the transaction needs to roll back, it will be undone automatically and will not be appended to the stack
        • In order to find out when rollback occurs, use the TransactionalCommandStack::execute(Command, Map) method, which throws RollbackException , instead of using CommandStack::execute(Command)
        • This method also accepts a map of options to configure the transaction that will be created (more on options, later)
    • 211. RecordingCommands
      • The RecordingCommand class is a convenient command implementation for read/write transactions
        • Uses the change information recorded (for possible rollback) by the transaction to “automagically” provide undo/redo
      TransactionalCommandStack stack; stack. execute (new RecordingCommand () { protected void doExecute () { Iterator iter = resource.getAllContents(); while (iter.hasNext()) { // changes are determined on-the-fly Object next = iter.next(); if (next instanceof Library) { ((Library) next).getBooks().add( LibraryFactory.eINSTANCE.createBook()); } } }}, Collections.EMPTY_MAP);
    • 212. Transaction Options
      • The TransactionalCommandStack::execute() method accepts a map of options defined by the Transaction interface that determine how changes occurring during the transaction are handled:
        • OPTION_NO_NOTIFICATIONS : changes are not included in post-commit change events
        • OPTION_NO_TRIGGERS : changes are not included in pre-commit change events
        • OPTION_NO_VALIDATION : changes are not validated
        • OPTION_NO_UNDO : changes are not recorded for undo/redo and rollback. Use with extreme caution!
    • 213. Transaction Options
      • (continued from previous slide)
        • OPTION_UNPROTECTED : implies OPTION_NO_UNDO , OPTION_NO_VALIDATION , and OPTION_NO_TRIGGERS . In addition, permits writing to the resource set even in an otherwise read-only context. Use with even more extreme caution!
      • The CommandStack::undo() and ::redo() methods use the following options for the undo/redo transaction:
        • OPTION_NO_UNDO : because we are undoing or redoing a previous recording, there is no need to record anew
        • OPTION_NO_TRIGGERS : triggers performed during execution were recorded and are automatically undone; any additional changes would be inappropriate
        • OPTION_NO_VALIDATION : there is no need to validate a reversion to a previous state of the data
    • 214. Transaction Options
      • The pre-defined options only apply to read/write transactions
        • Permitted on read-only transactions but have no effect
      • Extensions of the transaction API can define custom options
      TransactionalCommandStack stack; Library library; // don’t tell the UI that we are changing the library name stack. execute ( SetCommand.create(domain, library, EXTLibraryPackage.Literals.LIBRARY__NAME, &quot;Secret Name&quot;), Collections.singletonMap( Transaction. OPTION_NO_NOTIFICATIONS , Boolean.TRUE));
    • 215. Creating Read-Only Transactions
      • To read the contents of the resource set safely, use the runExclusive() API:
      TransactionalEditingDomain domain; domain. runExclusive (new Runnable () { public void run () { Iterator iter = resource.getAllContents(); while (iter.hasNext()) { Object next = iter.next(); if (next instanceof Library) { Library lib = (Library) next; System.out.println (lib.getName() + &quot; inventory: &quot; + lib.getBooks().size() + &quot; books&quot;); } } }}, Collections.EMPTY_MAP); Main Branch inventory: 3033 books West Branch inventory: 2570 books South Branch inventory: 1318 books
    • 216. Transaction Sharing
      • Read-only transactions on multiple threads can be interleaved by cooperatively yielding their read lock
        • Recommended for long-running read operations
        • Call TransactionalEditingDomain::yield() to yield read access to other threads waiting for read-only transactions
        • Yielding thread waits until other threads return read access to it either by finishing their transactions or by yielding
        • Yielding is fair: read access is always passed to the thread that has waited longest
      • Write access is not shared in this way
        • Readers cannot yield to writers
        • Writers cannot yield to any others
    • 217. Transaction Sharing final TransactionalEditingDomain domain; final IProgressMonitor monitor; // acquire read transaction on this thread domain. runExclusive (new Runnable () { public void run() { while (moreToRead()) { // … do a bunch of reading … readSomeStuff(); // checking the progress monitor is a good opportunity to // yield to other readers if (monitor.isCancelled()) { forgetIt(); break; } domain. yield (); // just returns if no readers waiting } }});
    • 218. Transaction Sharing
      • A thread that owns a transaction can lend it to another thread using a PrivilegedRunnable
        • The privileged runnable takes over the transaction for the duration of its run() method
        • Can be used to share read-only and read-write transactions
      • Ideal for runnables that need to access the resource set and the UI thread at the same time:
        • Pass the privileged runnable to Display.syncExec(Runnable) API to run on the UI thread
      • Must only be used with synchronous inter-thread communication such as syncExec
        • The originator thread loses the transaction during the runnable
    • 219. Transaction Sharing TransactionalEditingDomain domain; final org.eclipse.swt.widgets.List bookList; // acquire read transaction on this thread domain. runExclusive (new Runnable () { public void run() { // hand it off to the UI thread to read the library and update // the list widget Display.syncExec (domain. createPrivilegedRunnable ( new Runnable() { public void run () { // the UI thread now has the transaction List<String> bookTitles = new ArrayList<String>(); for (Book book : library.getBooks) { bookTitles.add(book.getTitle()); } } // the UI thread gives up the transaction }));
    • 220. Change Listeners
      • EMF provides an Adapter mechanism to notify listeners when objects change
        • In a transactional environment, though, we can end up reacting to changes only to find that they are reverted when a transaction rolls back
      • Enter the ResourceSetListener
        • Post-commit event notifies a listener of all of the changes, in a single batch, that were committed by a transaction
        • If a transaction rolls back, no event is sent because there were no changes
          • There are exceptions for changes that are not (and need not be) undone, such as resource loading and proxy resolution
    • 221. Change Listeners
      • ResourceSetChangeEvent provides the changes that occurred
        • Transaction additionally has a ChangeDescription summarizing the changes
      • Listeners can declare filters to receive only events of interest to them
      • ResourceSetListenerImpl is a convenient base class providing no-ops for the listener call-backs
    • 222. Change Listeners
      • Resource set listeners are added to the transactional editing domain
      • Listeners can be registered statically against an editing domain ID
        • Ensures that the listener is attached as soon as the domain comes into being
        • Resolves the problem of timing the addition of listeners
      domain. addResourceSetListener (new MyListener ()); <extension point=&quot; org.eclipse.emf.transaction.listeners &quot;> < listener class =&quot;com.example.MyListener&quot;> < editingDomain id =&quot;com.example.MyEditingDomain&quot;/> </listener> </extension>
    • 223. Post-Commit Listeners
      • A post-commit listener just overrides ResourceSetListenerImpl.resourceSetChanged()
        • DemultiplexingListener implements this by dispatching the notifications one by one to the handleNotification() method
      class MyListener extends ResourceSetListenerImpl { public void resourceSetChanged (ResourceSetChangeEvent event) { System.out.println(&quot;Domain &quot; + event .getEditingDomain().getID() + &quot; changed &quot; + event .getNotifications().size() + &quot; times&quot;); } } class MyDemuxedListener extends DemultiplexingListener { protected void handleNotification (TransactionalEditingDomain domain, Notification notification) { System.out.println(&quot;Domain &quot; + domain .getID() + &quot; changed: &quot; + notification .getNotifier()); } }
    • 224. Post-Commit Listeners
      • Advantages of the ResourceSetChangedEvent include:
        • Listeners know that the changes are permanent
        • Notifications can be processed efficiently as an aggregate
          • Don’t need to worry about dependency on “future” changes
        • No further changes can occur while the change event is being dispatched
          • Listeners are invoked in read-only transactions, so that they can safely read the resource set while analyzing the changes
      • Listeners need to be aware that notifications are delayed relative to the timing of the changes
        • Notifications are only received after all changes are complete
        • Any given notification may not correspond to the current state of the resource set, depending on subsequent changes
    • 225. Pre-Commit Listeners
      • Before a transaction closes, pre-commit listeners are notified of the changes performed
        • Listeners can provide additional changes, in the form of commands, to be appended to the transaction
          • As with post-commit listeners, the pre-commit listener is invoked in a read-only transaction, so it does not make changes “directly”
        • These commands implement proactive model integrity, as do triggers in RDBMS. Hence the term “trigger command”
      • Trigger commands are executed in a nested transaction
        • This procedure is recursive: the nested transaction also invokes pre-commit listeners when it commits
    • 226. Pre-Commit Listeners class MyListener extends ResourceSetListenerImpl { MyListener() { // only interested in changes to Library objects super(NotificationFilter. createNotifierTypeFilter ( EXTLibraryPackage.Literals.LIBRARY)); } public Command transactionAboutToCommit (ResourceSetChangeEvent event) { List commands = new ArrayList(); Iterator iter = event.getNotifications().iterator(); while (iter.hasNext()) { Notification next = (Notification) iter.next(); Library library = (Library) next.getNotifier(); if (library.getName() == null) commands.add( SetCommand.create ( event.getEditingDomain(), library, EXTLibraryPackage.Literals.LIBRARY__NAME, &quot;A library&quot;)); } return commands.isEmpty()? null : new CompoundCommand(commands) ; } }
    • 227. Pre-Commit Listeners
      • The TriggerListener class is convenient for processing notifications one by one, where appropriate
      class MyTriggerListener extends TriggerListener { MyListener() { // only interested in changes to Library objects super(NotificationFilter.createNotifierTypeFilter( EXTLibraryPackage.Literals.LIBRARY)); } protected Command trigger (TransactionalEditingDomain domain , Notification notification ) { Library library = (Library) next.getNotifier(); if (library.getName() == null) { return SetCommand.create(domain, library, EXTLibraryPackage.Literals.LIBRARY__NAME, &quot;A library&quot;); } return null; } }
    • 228. Transaction Validation
      • When a read/write transaction commits, all of the changes that it performed are checked using the Validation Framework’s live validation capability
        • If problems of error severity or worse are detected, then the transaction rolls back
      • Pre-commit listeners can also force the transaction to roll back by throwing a RollbackException
        • If a pre-commit listener cannot construct the command that it requires to maintain integrity, then it should roll back
    • 229. Transaction Nesting
      • Both read-only and read-write transactions can nest to any depth
      • Post-commit events are sent only when the root transaction commits
        • Because even after a nested transaction has committed, it can be rolled back if its parent (or some ancestor) rolls back
      • Pre-commit events are sent at every level of nesting
        • Because a parent transaction may assume data integrity conditions guaranteed by triggers when it resumes
      • Validation is performed on all changes when a root transaction commits
        • Because triggers must be invoked first, in nested transactions
    • 230. Transaction Nesting
      • Nested transactions inherit options from their parents
        • The standard options cannot be disinherited. e.g., if a parent transaction does not send post-commit notifications, then none of its descendents will, either, even if they explicitly specify Boolean.FALSE for that option
      • Nested transactions can, however, apply more options than their parents
        • e.g., a child transaction can disable notifications. When its parent commits, the changes that it reports will simply exclude any that occurred during the execution of the child
      • The inheritance of custom options in an extension of the transaction API is defined by that extension
    • 231. Transaction Lifecycle Overview
    • 232. UI Utilities
      • The Transaction API includes some utilities for building transactional editors
        • Use the editing domain to create read-only and/or read-write transactions as necessary
        • Substitute for the default EMF.Edit implementations
    • 233. Agenda
      • EMFT in a Nutshell
      • Validating Models
      • Querying Models
      • Working with Transactions
      • Working with the Operation History
      • Summary
    • 234. Workbench Integration
      • The WorkspaceEditingDomainFactory creates editing domains whose command stacks delegate undo/redo history to the Eclipse Workbench’s IOperationHistory
    • 235. Workbench Integration
      • To use the operation-history-enabled editing domain with your editor, simply register it with the appropriate factory class
      • The IWorkspaceCommandStack delegates to an operation history
        • Using IUndoContext s, editors for different resources in the same editing domain can provide undo/redo menus that show only the changes affecting that editor
      <extension point=&quot; org.eclipse.emf.transaction.editingDomains &quot;> <editingDomain id=&quot;com.example.MyEditingDomain&quot; factory=&quot; org.eclipse.emf.workspace.WorkspaceEditingDomainFactory &quot;/> </extension>
    • 236. EMF Operations
      • The command stack internally wraps EMF Command s in undoable operations and executes them on the operation history
      • Clients can also construct Abstract- EMFOperation s and execute them on the history
      • CompositeEMFOperation s can freely compose both EMF and non-EMF changes
    • 237. EMF Operations
      • AbstractEMFOperation s execute themselves within a transaction on their editing domain
        • Provides rollback support and automatic undo/redo just as the RecordingCommand does
      • CompositeEMFOperation s can compose EMF operations and operations on other domains
        • e.g., a composite can change objects in an EMF resource as well as edit parts in a GEF drawing surface and code in Java source files that are all interrelated
        • Undo/redo is fully supported and preserves ordering dependencies between EMF and non-EMF changes
        • Transaction rollback correctly undoes non-EMF changes
    • 238. EMF Operations IOperationHistory history = workbench.getOperationSupport() .getOperationHistory(); IUndoableOperation operation = new AbstractEMFOperation (domain, “ Create Books in Libraries”) { protected IStatus doExecute (IProgressMonitor monitor, Iadaptable info) throws ExecutionException { Iterator iter = resource.getAllContents(); while (iter.hasNext()) { // changes are determined on-the-fly Object next = iter.next(); if (next instanceof Library) { ((Library) next).getBooks().add( LibraryFactory.eINSTANCE.createBook()); } } return Status.OK_STATUS; }}; operation. addUndoContext (myEditorContext); history. execute (operation, new NullProgressMonitor(), null);
    • 239. Transaction Options
      • As is the case with Command s, EMF operations can execute with transaction options
        • A Map of options can be passed to the operation constructor. These are used during execution to initialize the transaction
      • The AbstractEMFOperation::undo() and ::redo() methods use the following transaction options:
        • OPTION_NO_UNDO : because we are undoing or redoing a previous recording, there is no need to record anew
        • OPTION_NO_TRIGGERS : triggers performed during execution were recorded and are automatically undone; any additional changes would be inappropriate
        • OPTION_NO_VALIDATION : there is no need to validate a reversion to a previous state of the data
    • 240. Resource Undo Context
      • The editing domain for workbench integration automatically applies contexts to operations that are executed on its history
        • For each resource affected by a transaction, a resource undo context is applied to the operation
        • A resource is affected by any change to an object that it contains or by a change in another resource that adds a cross-reference to it
        • An editor that uses a resource context as its editor context will populate its undo and redo menus with operations that affected its resource
    • 241. Undo/Redo Actions
      • The workbench integration API provides replacements for EMF’s undo/redo actions that delegate to the operation history API’s action handlers
      • These wrappers create undo/redo action handlers on the undo context obtained by adapting the active editor part to the IUndoContext type
        • Usually this undo context is a ResourceUndoContext
    • 242. Agenda
      • EMFT in a Nutshell
      • Validating Models
      • Querying Models
      • Working with Transactions
      • Working with the Operation History
      • Summary
    • 243. Summary
      • We have learned how to
        • validate EMF resources on demand and on-the-fly using the EMFT Validation Framework
        • search EMF resources using the EMFT Query Framework
        • implement data integrity in EMF resources in a concurrent programming environment using the EMFT Transaction API
        • integrate EMF-based editors with the Eclipse Workbench’s undo/redo framework using the EMFT Transaction API
    • 244. Resources
      • EMF documentation in Eclipse help
        • Overviews, tutorials, API reference
      • EMF project Web site
        • http://www.eclipse.org/modeling/emf/
        • Overviews, tutorials, newsgroup, Bugzilla
      • Eclipse Modeling Framework by Frank Budinsky et al.
        • Addison-Wesley; 1st edition (August 13, 2003)
        • ISBN: 0131425420.
    • 245. Resources
      • EMFT documentation in the Eclipse on-line help
        • Overviews, tutorials, and API reference (Javadocs)
      • EMFT components Web site
        • Home page: http://www.eclipse.org/emft
        • Newsgroup: news://news.eclipse.org/eclipse.technology.emft
        • Bugzilla: https://bugs.eclipse.org/bugs/
        • Wiki: http://wiki.eclipse.org/EMFT
    • 246. Legal Notices
      • IBM, Rational, WebSphere, Lotus, alphaWorks, and Rational Rose are registered trademarks of International Business Machines Corp. in the United States, other countries, or both.
      • Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both.
      • Other company, product, or service names may be trademarks or service marks of others.

    ×