Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "EMF/Recipes"

< EMF
(Code generation recipes)
(Recipe: Extend EContentAdapter to receive notifications from a whole containment tree)
Line 70: Line 70:
 
== Notification Framework Recipes ==
 
== Notification Framework Recipes ==
  
=== Recipe: Extend EContentAdapter to receive notifications from a whole containment tree ===
+
=== Recipe: Use EContentAdapter to receive notifications from a whole containment tree ===
  
 
'''Problem'''
 
'''Problem'''

Revision as of 09:34, 30 August 2007

This topic gathers recipe-style solutions for common needs developers using EMF have.

Code generation recipes

Recipe: Generating Pure API With No Visible EMF Dependencies

Problem

You want to generate code for an EMF model but you don't want any references to EMF types in your API or anything else that reveals that the API is implemented by EMF.

Solution

In your genmodel:

  • Set the 'Suppress EMF Types' property to 'true'; standard Java types will be used rather than EMF types for all accessors and operations. Features of type 'EObject' will be surfaced as 'java.lang.Object' instead. If the model includes feature maps, you will need to use the properties 'Feature Map Wrapper Class', 'Feature Map Wrapper Interface', and 'Feature Map Wrapper Internal Interface' to provide an alternative API. You can look as the support for SDO's Sequence API as the example.
  • Clear or set the value of the 'Root Extends Interface' generator model property. If cleared, the generated domain API will not depend on anything, or it can be set to an interface of your choosing so that root interfaces will extend this specified interface.
  • Set 'Suppress EMF Metadata' to 'true' so that only a package implementation class is generated, but no interface, and so that the generated factory interface will not extend EFactory and will have an INSTANCE instead of an eINSTANCE field. Alternatively, set the generator package's 'Metadata' property to redirect the package and factory interfaces to a different Java subpackage.
  • Set the 'Suppress EMF Model Tags' property to 'false' to eliminate the generation of the @model tags in the Javadoc.
  • Set the 'Root Extends Class' and 'Root Implements Interface' properties to control the generation of the implementation, but if you clear the first one or set it so the generated implementation is not a subclass of EObjectImpl, the generated code will be invalid as it will have unresolved references to inherited methods that will not be available, e.g., eGet, eSet, eUnset, eIsSet and eIsProxy. Generating an implementation that is pure Java is not possible with the default templates but can be achieved with dynamic templates.

Related recipes

None so far.

References



Recipe: Using Multiple Namespaces in the Generated EMF Editor

Problem

You want to use multiple namespaces in your generated EMF editor: say you have metamodel A with namespace mm.A which is a superset of legacy metamodel B with namespace mm.B .

If you generate an EMF editor using namespace mm.A, it can by default not read files which were serialized using namespace mm.B, unless you manually edit the files to point to namespace mm.A. But all files using metamodel B must be compatible with some legacy tool so they cannot be changed.

Now you could rename namespace mm.A to mm.B and regenerate the editor, but that forces you to adapt all your manual code and all your new files using metamodel A.

Solution

  • You can change your plugin.xml to let the editor recognize both namespaces:
<extension point="org.eclipse.emf.ecore.generated_package">
  <package
     uri = "mm.B"
     class = "mm.APackage"
</extension>
<extension point="org.eclipse.emf.ecore.generated_package">
  <package
     uri = "mm.A"
     class = "mm.APackage"
     genModel = "model/A.genmodel" />
</extension>
  • If you save a model in your generated EMF editor, it will by default use namespace mm.A. You can change it to save using namespace mm.B by changing the String eNS_URI in src/mm.APackage (and changing the @generated tag).

Related recipes

None so far.

References


Notification Framework Recipes

Recipe: Use EContentAdapter to receive notifications from a whole containment tree

Problem

You want to observe changes in a whole containment tree.

Solution

  • Extend org.eclipse.emf.ecore.util.EContentAdapter (MyContentAdapter) and add that extension as an Adapter to the Root EObject of the containment hierarchy that you want to observe.
  • Override the method 'notifyChanged(Notification n)'. Inside the method´s body your first call must be super.notifyChanged(n) which adds MyContentAdapter to any new elements in the hierarchy and removes MyContentAdapter from any removed EObjects in the hierarchy. After finding out the type of the notifier Object (Remember: this might now be any EObject in the containment hierarchy, not just the EObject you initially added MyContentAdapter to - so it could be of any type that occurs in the containment hierarchy) you can go on by writing the usual notification code to find out about what feature changed, the type of the notification, etc.

Example

A simple example model org.example.library consists of an EClass 'Library' which has a containment reference 'books' of type 'Book'. The EClass 'Book' has a String attribute 'title' and a boolean attribute 'available'. Now you want to be notified about a) new Books in the Library and b) about changes of any book´s availability (the title of a book usually won´t change so we exclude this feature). Using the Solution described above we will do the following:

class MyContentAdapter extends org.eclipse.emf.ecore.util.EContentAdapter {

    // start observing a Library model
    public void observeLibrary(org.example.library.Library l){
        l.eAdapters().add(this);
    }

    //override the notifyChanged method
    public void notifyChanged(Notification n){
        
        super.notifyChanged(n); // the superclass handles adding/removing this Adapter to new Books
        
        // find out the type of the notifier which could be either 'Book' or 'Library'
        Object notifier = Notification.getNotifier();
        if (notifier instanceof Library) {
            handleLibraryNotification(n);
        } else if (notifier instanceof Book) {
            handleBookNotification(n);
        }
    }

    // output a message about new books
    private void handleLibraryNotification(Notification n){
        int featureID = n.getFeatureID(org.example.library.Library.class);
        if (featureID = org.example.library.LibraryPackage.LIBRARY__BOOKS){
            if (n.getType == Notification.ADD){
                Book b = (Book) n.getNewValue(); 
                System.out.println("New Book was added to the Library: + " b.getTitle());
            }
        }
    }

    // output a message about a book´s availability
    private void handleBookNotification(Notification n){
        int featureID = n.getFeatureID(org.example.library.Book.class);
        if (featureID == org.example.library.LibraryPackage.BOOK__AVAILABLE){
                Book b = (Book) n.getNotifier();
                System.out.println("The book " + b.getTitle() + " is now " + (b.isAvailable() ? "available" : "unavailable"));
        }
    }
}

Related Recipes

None so far.

References

  • Thread on the EMF newsgroup: "[1]"

Copyright © Eclipse Foundation, Inc. All Rights Reserved.