11
Eclipse Modeling Framework – Tips n Tricks 1. Design a Model Provider API Always invoke the singleton instance of a ModelProvider from anywhere in the application as a single point contact for managing the lifecycle and behavior of model Ø It should contain the corresponding editing domain, file resource, resource set, associated editor part, navigator and tabbed propertypage sheet Ø It should maintain a single copy of the domain model in the memory. getModel(IResource resource) Ø It should maintain the list of cross-references Ø It should be a resource-change listener so that o it can un-load the model and delete the emf resource when the file resource is deleted o It can modify the resource-uri when the file is moved / renamed Ø Whenever the resource uri is changed then using EcoreUtil CrossReferencer ModelProvider should find out what all models should be refactored Ø ModelProvider should also register all required ItemAdapterFactories Ø It should provide the custom persistence policy for the model if needed 2. Item Provider is the single-most powerful feature in EMF. They should be utilized to the fullest. It provides the functions to Ø Implement content and label provider

EMF Tips n Tricks

Embed Size (px)

DESCRIPTION

EMF Advanced Tips

Citation preview

Page 1: EMF Tips n Tricks

Eclipse Modeling Framework – Tips n Tricks

1. Design a Model Provider API

Always invoke the singleton instance of a ModelProvider from anywhere in the application  as a single point contact for managing the lifecycle and behavior of model

Ø  It should contain the corresponding editing domain, file resource, resource set, associated editor part, navigator and tabbed propertypage sheet Ø  It should maintain a single copy of the domain model in the memory.

getModel(IResource resource) Ø  It should maintain the list of cross-references Ø  It should be a resource-change listener so that o                  it can un-load the model and delete the emf resource when the file resource is deleted o                  It can modify the resource-uri when the file is moved / renamed Ø  Whenever the resource uri is changed then using EcoreUtil CrossReferencer ModelProvider should find out what all models should be refactored Ø  ModelProvider should also register all required ItemAdapterFactories Ø  It should provide the custom persistence policy for the model if needed

2. Item Provider is the single-most powerful feature in EMF.  They should be utilized to the fullest. It provides the functions to

Ø    Implement content and label provider By using mixin interfaces – delegate pattern Public Object[] getchilren(Object object){      ITreeItemContentProvider  adapter =  (ITreeItemContentProvider )       adapterFactory.adapt(object, ITreeItemContentProvider  .class);      return aapter.getChildren(object).toArray(); }

Ø    Adapt the model objects to implement whatever interfaces the editors and views need. Ø    Propagate  the change-notifications to viewers Ø    Act as command factory Ø    Provide a property source for model objects

3.   Effective usage of Common Command Fwk

getResult() should be overridden to return relevant model objects  so that (1)             result of one command can be input to another command

Page 2: EMF Tips n Tricks

(2)             the required diagram element or xml node or language statement or property section can be selected and highlighted

getAffectedObjects()

4. WorkingModel – should be reloaded when the resource is modified/deleted if (workingModelListener == null) { workingModelListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) {                                        if (WorkingModel.PROP_DIRTY.equals(evt.getPropertyName())) {                                                                                 editorDirtyStateChanged();                                             } else if (WorkingModel.PROP_RELOADED.equals(evt.                   .getPropertyName())) {      reloadModel((IFile) getWorkingModel()                                  .getEclipseResources().get(0));                                         } else if (WorkingModel.PROP_REMOVED.equals.getPropertyName())) {                      Object newLocation = evt.getNewValue();                     if(newLocation == null) {                cleanupModelCopyOfDeletedResource();               close(false);                                                        }else if (newLocation instanceof IPath) {                                                  // file is renamed IFile newFile = ResourcesPlugin.getWorkspace()                                  .getRoot().getFile( (IPath) newLocation);                               if (newFile != null && newFile.exists()) {                                                                  reloadModel(newFile);                                         } else {                                                                    close(false);                                                                  }                                          } else {                                                                          close(false);                                                                  }             5. How to find EMF References ?  private Node findReferingModel(EObject eo) {   Collection<Setting> referrers = EcoreUtil.UsageCrossReferencer.find(eo,                                                         eo.eResource());   Iterator<Setting> it = referrers.iterator();    while (it.hasNext()) {          Setting referer = (Setting) it.next();          EObject referredObj = referer.getEObject();          return referredObj;

Page 3: EMF Tips n Tricks

  } 6. Why Notification Listeners in EMF are also called Adapters ?

A. Apart from observing the changes in eObjects, they also help - extending the behavior i.e. support additional interfaces without subclassing - (Adapter pattern)   Attaching an Adapter as Observer :   Adapter myEObjectObserver = ... myEObjectObserver.eAdapters().add(myEObjectObserver);   Attaching an Adapter as a Behaviour Extension :   MyEObject myEObject = .... AdapterFactory myEObjectAdapterFactory = .... Object myEObjectType  <== if(myEObjectAdapterFactory.isFactoryType(myEObjectType )){ Adapter myEObjectAdapter =        myEObjectAdapterFactory.adapt(myEObject, myEObjectType); ..... }   Attaching an adapter to all the eobjects under the root   So far we have seen how to adapt to the changes to a particular EObject.   Q. Now how to adapt to all the objects in the containment hierarchy, a resource and a set of related resources : EContentAdapter - can be attached to a root object, a resource or even a resourseset.   7. What is resource-proxy and on-demand resource loading ?

A. Say PO Entity simply refers to an Item Entity i.e. there is no by-value aggregation/strong composition i.e. no containment reference between PO and Item EObjects.   Basically there is a cross-document reference   So in this case there will be one poReource with poURI and an itemResource with itemURI.  

Page 4: EMF Tips n Tricks

When we call rsourseSet.getReource(poURI) --> the ResourseSet will start traversing the resource eobject-tree and load all eObjects. But for any references to objects in itemResource , instead of traversing itemResource the ResourseSet will set the references to Proxies (* an uninitialized instance of the actual target class * with the actual URI).   When - po.getItem() - will be invoked, the proxies will be resolved and actual Item EObjects will be loaded on demand.   8. How to get the objects modified during the last execute() / undo() / redo() ? >> command.getAffectedObjects()   These objects should be used for selecting/highlighting the viewers   9.Some useful Commands : >> Moving objects up - down in Viewer  : MoveCommand >> Replacing an object in multiplicity-many features : ReplaceCommand >> Creating a duplicate object : CopyCommand >> Create a new object and add it to a feature of EObject : CreateChildCommand >> Delete an eobject from parent container along with all references : DeleteCommand   10. What is the role of Editing Domain ?   AdapterFactoryEditingDomain -- (i) creates command thru item provider, (ii) maintaining editor's commandstack, (iii)  maintaining resource set   11. Ecore Model Optimization " >> If a particular reference is always -containment- and can never be cross-document; then resolveProxies should be set to false

11. How to define a custom data type ? >> We should not refer a highly complicated Java Class as data type. >> Instead we should model the Java_Class as EClass and then create an EDtaType where instanceClass should refer to that EClass.

12. How to maintain in-memory temporary ELists which need not be persisted ? These model elements should be declared as - volatile, transient, non-changeable and deived.

public EList getSpecialModelObjects(){    ArrayList specialModelObjects = new ArrayList();    for(...  getmodelObjects() ... ){

Page 5: EMF Tips n Tricks

     if(...){        specialModelObjects.add();     }   } return new ECoreEList.UnmodifiableEList(this, , specialComposites.siz(), specialComposites.toArray()); }

13. What to do if you want to create a unique list which should contain elements of a particular type ?     Elist locations = new EDataTypeUniqueEList(String.class, this,     EPO2Package.GLOBAL_ADDRESS_LOCTION);

14. How to suppress creation of eobjects ? Simply clear the GenModel property – “Root Extends Interface” –

15. How to control the command's appearance i.e. decorate the actions ?

The item provider is an IchangeNotifier to support DECORATOR pattern – an ItemProviderDecorator registers itself as a listener for the Item Provider that it decorates. The commands need to implement CommandActionDelegate interface to provide implementation for retrieving images and labels.

16. How to use custom adapter factories ? Create a ComposedAdapterFactory and include the item provider for the classes that are not part of the model along with the regular item provider factories.

17. How to refresh a viewer and set the selection on particular elements ?

editingDomain.getCommandStack().addCommandStackListener( new CommandStacklistener() { public void commandStackChanged(final EventObject event) {                    getContainer().getDisplay().asyncExec( new Runnable() {                    public void run() {                    firePropertyChange(IEditorPart.PROP_Dirty); Command mostRecentCommand = ((CommandStack)event.getSource()).getMostRecentCommand(); if (mostRecentCommand != null) {                    setSelectionToViewer(mostRecentCommand.getAffectedObjects()); } // ---  set selection

Page 6: EMF Tips n Tricks

if (propertySheetPage != null && !propertySheetPage.getControl().isDisposed()) {     propertySheetPage.refresh(); }            );    });

18. How to use the Item Provider Factories as Label and Content Providers ? >>  selectionViewer.setContentProvider(new AdapterFactoryContentProvider(composedAdapterFactory)); >>  selectionViewer.setLabelProvider(new AdapterFactoryLabelProvider(composedAdapterFactory));

19. Remember Action Bar Contributor – invokes the child-descriptors as specified by the item-providers to create the actions.

20. How to register a custom Resource Factory against a file type ? resourceSet.getRespourceFactoryRegistry().getExtensionToFactoryMap().put(“substvar”, new SvarResourceFactoryImpl())

21. While creating URI if the file path contains space, use encoding mechanism.

URI.createURI(encoding_flag) …

18. How to encrypt/decrypt the stream data ?

Save/Load  OPTION_CIPHER, OPTION_ZIP (URIConverter.Cipher) DESCipherImpl → CryptoCipherImpl 

19. How to query XML data using EMF ?

XMLResource resource  = (XmlResource)rs.createResource(    URI.createPlatformResourceURI(“/project/sample.xml”, true)); resource.getContents().add(supplier); Map options = new HashMap(); options.put(XMLResource.OPTION_KEEP_DEFAULT_CONTENT, Boolean.TRUE); Document document = resource.save(null, options, null); DOMHelper helper = resource.getDOMHelper(); NodeList nodes = XpathAPI.selectNodeList(document, query) for(...) { Node node = nodes.item(i)

Page 7: EMF Tips n Tricks

Item item = (Item)helper.getValue(node); }

20. How to serialize and load qname correctly ?

A. First we need to set the option OPTION_EXTENDED_META_DATA as true for loading and saving element in the MyResourceFactoryImpl#createResource() :

XMLResource result = new XMLResourceImpl(uri);result.getDefaultSaveOptions().put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE);result.getDefaultLoadOptions().put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE);

B. Always use - AddCommand / RemoveCommand / SetCommand / EMFOpertionCommand / EMFCommandOperation - instead of RecordingCommand ; because RecordingCommand does not load / store QNames properly while undoing/redoing. I have raised a Bug in Eclipse that I shall post here soon …

21. How to load emf resource from a plugin jar ?

Lets assume that an emf resource file has been contributed to an extension-point.Now while reading the extension points; one can find out the name of the plugin.

IConfigurationElement[] elements = extensions[i].getConfigurationElements();IContributor contributor = elements[j].getContributor();String bundleId = contributor.getName();

URI uri = URI.createPlatformPluginURI("/" + bundleId + "/"+ filePath, true);Resource resource = ResourceSetFactory.getResourceSet().createResource(uri);resource .load(null);EList contents = resource .getContents();

22. How to customize the copy functionality of EcoreUtil ?

EcoreUtil.Copier testCopier = new Ecoreutil.Copier() {

protected void copyContainment(EReference eRef, EObject eObj, EObject copyEObj) {// skip the unwanted featureif(eRef != unwanted_feature) {super.copyContainment(eRef, eObj, copyEobj);}

Page 8: EMF Tips n Tricks

}//testCopier.copyAll(testObjects);testCopier.copyReferences();//