EMF/Recipes

From Eclipsepedia

< EMF
Revision as of 13:59, 1 October 2007 by Merks.ca.ibm.com (Talk | contribs)

Jump to: navigation, search

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

Contents

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]"

Properties Recipes

Recipe: Create your own property editor in a generated application

Problem

You want to edit your model properties using your own cell editor, rather than using EMF default one.

Solution

  • Create your own CustomizedPropertyDescritor that extends 'org.eclipse.emf.edit.ui.provider.PropertyDescriptor' and overrides 'CellEditor createPropertyEditor(Composite)'. In that method create your own CellEditor. Please refer to super implementation to know, how to enable your editor for particular types.
  • Create your CustomizedPropertySource that extends 'org.eclipse.emf.edit.ui.provider.PropertySource.class' and overrides 'IPropertyDescriptor createPropertyDescriptor(IItemPropertyDescriptor)'. The overidden method should return CustomizePropertyDescriptor described in the previous paragraph.
  • Create your CustomizedAdapterFactoryContentProvider that extends 'org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider' and overrides 'IPropertySource createPropertySource(Object, IItemPropertySource)' method. The overidden method should return CustomizedPropertySource.
  • In your generated .editor find the XyzEditor, and then, in 'IPropertySheetPage getPropertySheetPage()' replace the line

propertySheetPage.setPropertySourceProvider(new AdapterFactoryContentProvider(adapterFactory)); with a line that will set your CustomizedAdapterFactoryContentProvider.

Example

  /**
   * This accesses a cached version of the property sheet.
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   * @generated NOT
   */
  public IPropertySheetPage getPropertySheetPage()
  {
    if (propertySheetPage == null)
    {
      //...

      propertySheetPage.setPropertySourceProvider
        (new AdapterFactoryContentProvider(adapterFactory)
         {
           @Override
           protected IPropertySource createPropertySource(Object object, IItemPropertySource itemPropertySource)
           {
             return 
               new PropertySource(object, itemPropertySource)
               {
                 @Override
                 protected IPropertyDescriptor createPropertyDescriptor(IItemPropertyDescriptor itemPropertyDescriptor)
                 {
                   return 
                     new PropertyDescriptor(object, itemPropertyDescriptor)
                     {
                       @Override
                       public CellEditor createPropertyEditor(Composite composite)
                       {
                         // Test for your case based on the feature or the type of the feature.
                         // See the super method for details.
                         //
                         Object feature = temPropertyDescriptor.getFeature(this.object);
                         return super.createPropertyEditor(composite);
                       }
                     };
                 }
               };
           }
         });
    }

    return propertySheetPage;
  }


Related Recipes

None so far.


References

  • Thread on the search result: "[2]"