| <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| <html> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| <meta name="GENERATOR" content="Mozilla/4.6 [en] (WinNT; I) [Netscape]"> |
| <title>Using EMF</title> |
| <link rel="stylesheet" href="../../default_style.css"> |
| </head> |
| <body link="#0000FF" vlink="#800080"> |
| |
| <div align=right> <font face="Times New Roman, Times, serif"><font size=-1>Copyright |
| © 2002 International Business Machines Corp.</font></font></div> |
| |
| <div ALIGN=right><table BORDER=0 CELLSPACING=0 CELLPADDING=2 WIDTH="100%" > |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2" BGCOLOR="#0080C0"><b><font face="Arial,Helvetica"><font color="#FFFFFF"> Eclipse |
| Corner Article</font></font></b></td> |
| </tr> |
| </table></div> |
| |
| <h1> |
| <img SRC="images/Idea.jpg" height=86 width=120 align=CENTER></h1> |
| |
| <center> |
| <h1> |
| Using EMF</h1></center> |
| |
| <blockquote><b>Summary</b> |
| <br> |
| This article introduces EMF, the Eclipse Modelling Framework, and will help |
| you get started using EMF in your own Eclipse plug-ins. |
| <p><b>By Catherine Griffin, IBM</b><br> |
| <font size=-1>December 9, 2002 (revised May 2003 for EMF 1.1.0)</font></blockquote> |
| |
| <hr width="100%"> |
| <h1> |
| What is EMF, and why would I want to use it ?</h1> |
| EMF, the Eclipse Modelling Framework, is used to define and implement structured |
| data models. A data model is simply a set of related classes used to handle |
| the data which you want to deal with in your application. |
| <h2> |
| Some good reasons to use EMF</h2> |
| |
| <ol> |
| <li> |
| <b>Code generation.</b> All the code needed for a working data model is generated for you, |
| based on a definition of the model. EMF generates nice readable code, from template files |
| that can be customized. You can customize the generated code, and your |
| changes won't be lost when the classes are regenerated. The input to code |
| generation can be a Rational Rose model file, annotated Java interfaces, |
| or an XML schema definition (under development).</li> |
| |
| <li> |
| <b>Meta-data.</b> You can programatically query the structure of a model, and |
| get more information than the standard Java BeanInfo or reflection would |
| allow. EMF also supports accessing and updating models reflectively.</li> |
| |
| <li> |
| <b>Default serialization.</b> EMF can load and save instances of your model as |
| XMI (an XML format). If you need to save your data in a different format, |
| you can do so. XML schema as a file format is under development.</li> |
| |
| <li> |
| <b>Links between files.</b> You can save and edit data across multiple files.</li> |
| |
| <li> |
| <b>Editors.</b> EMF will also generate an editor for your model, |
| complete with content outline and property sheet. There is also a reflective editor, |
| which can view and edit any EMF model file, using only the model meta-data. |
| It provides similar function to the default generated editor, but it can't be easily |
| customized. |
| </li> |
| </ol> |
| For more information see the <a href="http://www.eclipse.org/emf" target="_blank">EMF |
| project page</a>. |
| <p>If you want to try the example from this article, you will need EMF |
| and a suitable version of Eclipse (I am using 2.1). EMF version 1.1.0 |
| Build 20030501_0612VL was used to generate the example code. |
| <h1> |
| Developing an Eclipse plug-in using EMF</h1> |
| |
| <h2> |
| The Example</h2> |
| The example used in this article is an editor for family trees. |
| |
| <h2> |
| Step 1: Designing the model</h2> |
| The first step is to design the data model for the application - that is, the |
| structure of the data we want to be able to view and edit, and the relationships |
| between data items. You may find a UML tool useful, or a piece of paper. For this |
| application, the main information needed is who had which children. In UML, the |
| data structure looks like this: |
| <p align="center"><img src="images/familytree.JPG"></p> |
| A FamilyTree contains families and individuals. Individuals are either Male or |
| Female - Individual itself is an abstract class. A Family contains children and |
| is linked to a mother and father. |
| <p>In addition to these types of relations, EMF will handle multi-valued |
| references, two-way relationships (navigable both ways), enumerations and |
| data types (Java objects which aren't EMF based, serialized as strings). |
| <h2> |
| Step 2: Defining the model</h2> |
| The next step is to define the model to EMF so that code can be generated. |
| If you have Rational Rose, EMF can generate the implementation of your |
| model directly from the Rose mdl file. See the EMF tutorial for details. |
| <p>It is also possible to generate the model code from annotated Java interfaces. |
| and that is what is described below. If you don't want to do any typing, |
| just create a new Java project in Eclipse, import <a href="family1.zip">family1.zip,</a> |
| and skip to Step 3. Otherwise proceed as follows: |
| <ol> |
| <li> |
| In Eclipse, create a new Java project and a package for the interfaces. |
| I am calling my project <b>com.ibm.example.familytree</b> and my package |
| <b>com.ibm.example.familytree</b>.</li> |
| |
| <li> |
| Create new Java interfaces called FamilyTree and Family in this package. |
| In the Javadoc comment for each interface, add a line with the tag <b>@model</b>. |
| This tells EMF that this interface is part of your model.</li> |
| |
| <li> |
| A Java interface is also needed for Individual, but this needs an extra |
| piece of information in the Javadoc comment because Individual needs to |
| be treated as an abstract class. Add the tag <b>@model abstract="true"</b>.</li> |
| |
| <li> |
| Next create the interfaces Male and Female, each extending Individual. |
| Again add the <b>@model</b> tag.</li> |
| </ol> |
| |
| <h3> |
| Defining Attributes</h3> |
| Individuals have names, so we need to add the attribute 'name' to the Individual |
| interface. Just add a method as follows: |
| <pre> /** |
| * Return the individuals name. |
| * @return the name |
| * @model |
| **/ |
| String getName();</pre> |
| Again, the <b>@model</b> tag tells EMF that this method needs some code |
| generated. If you add methods to the interface that don't have the <b>@model</b> |
| tag, EMF will not generate implementations of those methods, so you will |
| have to implement them yourself. Sometimes it makes sense to do this - |
| for example, you might want to add some convenience methods to the model |
| interfaces. |
| <h3> |
| Defining simple references</h3> |
| A Family should have references to a mother and a father. Add the following |
| methods to the Family interface: |
| <pre> /** |
| * Return the father |
| * @return the father |
| * @model |
| **/ |
| <img SRC="images/tag_1.gif" height=13 width=24 align=CENTER> Male getFather(); |
| |
| /** |
| * Return the mother |
| * @return the mother |
| * @model |
| **/ |
| Female getMother();</pre> |
| Notice that the method <img SRC="images/tag_1.gif" height=13 width=24 align=CENTER> |
| is very similar to how an attribute is defined. |
| <h3> |
| Defining containment relations</h3> |
| In the UML model above, the links with black diamonds on them are containment |
| relations. For example, an Individual can be contained either by a Family |
| or by a FamilyTree. An object can only have one container. For example, |
| the relations between Family and Individual defined in the previous section |
| are not containment relations - because people can be married more than |
| once (even if generally not at the same time). |
| <p>When instances of this model are created using the editor generated |
| by EMF, there will be a single top-level FamilyTree object and all the |
| other objects in the model will be contained by it, directly or indirectly. |
| The model cannot be saved correctly if there are objects which have no |
| container. |
| <p>Add the following methods to FamilyTree to define its containment relations: |
| <pre> /** |
| * Return a list of contained families |
| <img SRC="images/tag_2.gif" height=13 width=24 align=CENTER> * @model type="Family" containment="true" |
| **/ |
| java.util.List getFamilies(); |
| |
| /** |
| * Return a list of contained individuals |
| * @model type="Individual" containment="true" |
| **/ |
| java.util.List getIndividuals(); |
| </pre> |
| Unlike the simple references defined in the previous section, these methods |
| return Lists - thats because a FamilyTree can contain multiple Families |
| and Individuals. The return type must be java.util.List or org.eclipse.emf.common.util.EList |
| so that EMF recognizes that this is meant to be multi-valued. Notice the |
| <b>@model</b> tag <img SRC="images/tag_2.gif" height=13 width=24 align=CENTER> |
| declares the type of object that can appear in the List. In addition, the |
| flag <b>containment="true"</b> indicates that this is a containment relation. |
| <p>There is one other containment relation to define, in Family: |
| <pre> /** |
| * Return children |
| * @return list of child Individuals |
| * @model type="Individual" containment="true" |
| **/ |
| java.util.List getChildren();</pre> |
| |
| <h2> |
| Step 3: Generating the model</h2> |
| Now that the model has been defined, we can proceed to generate the model |
| implementation. |
| <ol> |
| <li> |
| In the File menu, select <b>New > Other...</b></li> |
| |
| <li> |
| In the New File wizard, select <b>Ecore Model Framework</b> in the left-hand |
| panel and <b>GenModel model</b> in the right-hand panel, then click <b>Next</b>.</li> |
| |
| <li> |
| On the next page, select your project source folder, enter a filename with |
| file type "genmodel", and click <b>Next</b>.</li> |
| |
| <li> |
| Select the <b>Load from Java annotations</b> radio button and click <b>Finish</b>. |
| Two new files will be created in your project folder, one is called <b>familytree.ecore</b> |
| (this is an XMI file which contains a definition of the family tree model) and the other is the |
| genmodel file which you entered a name for. The genmodel file contains additional information about |
| how EMF should generate code for the model. The genmodel file is opened for editing. |
| </li> |
| |
| <li> |
| In the editor, select the root (first) node of the tree and right-click |
| to bring up the popup menu.</li> |
| |
| <li> |
| Select <b>Generate Model</b> to generate the model implementation code.</li> |
| </ol> |
| <p> |
| Two new packages will be generated in your project, <b>com.ibm.example.familytree.impl</b> and |
| <b>com.ibm.example.familytree.util</b>. |
| If you look now at the original package <b>com.ibm.example.familytree</b>, you will find that |
| two new interfaces called FamilytreeFactory and FamilytreePackage have appeared. These are used to |
| programmatically create model elements and to query meta-data, respectively. |
| At the same time as generating the model implementation, EMF has also made some changes to the other interfaces |
| in this package. If you look at Family.java for example, you will see that the return type java.util.List |
| has been changed to EList and that the interface now extends EObject. These changes are needed so that |
| the generated model code works correctly. |
| |
| |
| |
| <h2> |
| Step 4: Generating an editor</h2> |
| The popup menu in the GenModel editor has four generation options: |
| <ul> |
| <li> |
| <b>Generate Model</b> - generates the model implementation code, as you |
| have just seen.</li> |
| |
| <li> |
| <b>Generate EMF.Edit </b>- generates an extra plug-in containing adapter |
| classes needed by the generated editor.</li> |
| |
| <li> |
| <b>Generate EMF.Editor</b> - generates an editor plug-in for your model.</li> |
| |
| <li> |
| <b>Generate All </b>- generates the model, edit plug-in and editor.</li> |
| </ul> |
| Since we have already generated the model, to generate the editor we need |
| to first generate the EMF.Edit plug-in, then the EMF.Editor plug-in. This |
| creates two new plug-in projects called <b>com.ibm.example.familytree.edit</b> |
| and <b>com.ibm.example.familytree.editor</b>. |
| <h2> |
| Step 5: Trying out the generated plug-ins</h2> |
| The generated editor can be used as a starting point for developing your |
| application. However, resist the temptation to immediately start working |
| on fancier views. First use the generated editor to check that your data |
| model is able to cope with some sample data. If you find problems, you |
| can then redesign the data model and repeat the process until you are happy |
| with it. Its much easier to change your model now, than it would be after |
| you have put a lot of work into the editor. |
| <p>To run the example editor, you need to start a runtime workbench, making |
| sure that it will be launched with the three generated plug-ins. If you |
| aren't sure how to do this, see the EMF tutorial. |
| <p>Once the workbench has started, you need to create a model file: |
| <ol> |
| <li> |
| Create a new simple project</li> |
| |
| <li> |
| Select from the menu <b>File > New > Other...</b></li> |
| |
| <li> |
| Select <b>Example EMF Model Creation Wizards</b> and <b>Familytree Model</b>, |
| and click |
| <b>Next</b></li> |
| |
| <li> |
| Select the new project, and enter a filename for the new file. The file |
| should have the extension 'familytree'. Click Next.</li> |
| |
| <li> |
| From the combo box, select <b>FamilyTree</b>, then click <b>Finish</b>.</li> |
| </ol> |
| The new file will be opened with the editor. This is a multipage editor, |
| each page demonstrating different ways of displaying data from your model. |
| The first page is a tree view, the root of the tree being the file you |
| are editing. Expand the root and you will see a FamilyTree element - thats |
| what the wizard created in the file. Select FamilyTree and right-click |
| to bring up the popup menu. The menu allows you to add child elements - |
| Family, Female or Male. |
| <p>Add a Female or Male to the FamilyTree. If the Properties view is showing, |
| you should see the properties for the Individual - there is only one: name. |
| Set the name to something meaningful, and the label in the tree view will |
| change. |
| <p>When you add children to a Family, they appear as child items in the |
| tree. You can use the properties view to set the mother and father for |
| a Family, but setting these doesn't change the tree, because mothers and |
| fathers are linked to families, not contained by them. |
| <p>This is what the editor looks like when I have put in some test data: |
| <p align="center"><img SRC="images/testdata.JPG"></p> |
| |
| <p>The test family tree shown here is in the file <a href="Test.familytree">Test.familytree</a>. |
| This is an XMI file. By default, EMF uses XMI (a form of XML) to save model instance data. |
| If you need to save your data in a different format, you can write code to do so. |
| <h2> |
| Anatomy of the EMF Editor</h2> |
| As you can see, the editor generated by EMF does quite a lot. The content |
| outline view (bottom left in the above image) shows the contents of the |
| file you are editing as a tree view. Whatever element is selected in the |
| content outline view is also shown selected on the first page of the editor, |
| which is a similar tree view. Whenever you select an element either in |
| the editor or in the outline, its properties are shown in the properties |
| view. The properties view lets you edit all that elements attributes and |
| any single-valued references to other model elements (by picking from all |
| the available elements of the right type). |
| <p>You can drag and drop elements to move them, and cut, copy and paste, delete, |
| undo and redo edit actions are supported. |
| <p>The other pages of the editor are - |
| <ul> |
| <li> |
| <b>Parent </b>- whatever element is selected in the outline view, this |
| tree view shows you how that element is contained.</li> |
| |
| <li> |
| <b>List</b> - this page shows a list of elements contained by the selected |
| element.</li> |
| |
| <li> |
| <b>Tree</b> - same thing again, in a tree view</li> |
| |
| <li> |
| <b>Table</b> - a table view of the children of the selected model element.</li> |
| |
| <li> |
| <b>TableTree</b> - same again, using a table tree control.</li> |
| </ul> |
| |
| <h1> |
| Next steps</h1> |
| You might decide at this point that some changes to the model are needed. |
| For example, say I want to add a description attribute to Individual so |
| I can add additional biographical information. I would edit the Individual |
| interface as before and add the method: |
| <pre> /** |
| * Return a description. |
| * @return a description |
| * @model |
| **/ |
| String getDescription();</pre> |
| Then to update the genmodel file, right-click on it to bring up the popup |
| menu, and select <b>Reload...</b>. You will also need to regenerate all |
| the generated code. If you make changes to the generated code, then remember |
| to take out the <b>@generated</b> flag from the Javadoc so that your changes |
| are not overwritten. |
| <p>The generated editor is meant to be a starting point for your own development |
| and a demonstration of the reusable user interfaces parts provided in EMF. |
| Once you are satisfied that your model is how you want it to be, you can |
| start customizing the generated editor, or writing your own. |
| <h2> |
| Source code</h2> |
| To run the customized versions of the family tree plug-ins, unzip <a href="family2.zip">family2.zip</a> |
| into your <i>plugins/ </i>subdirectory. All the source code is included. |
| The customized editor has only two pages, the original first page and a |
| modified table tree view. For details of the changes see the sections below. |
| <h2> |
| Labels and Images</h2> |
| To change the labels that are used in the editor, you need to go and find |
| the adapter classes generated in the <b>com.ibm.example.familytree.edit</b> |
| project. In the package <b>com.ibm.example.familytree.provider</b>, there |
| is one adapter class for each model class. The methods <b>getText</b> and |
| <b>getImage</b> determine the label and image that are used in the editor. |
| <p>If you change the <b>getText</b> method, remember to remove the <b>@generated</b> |
| flag from the method javadoc comment so that your changes will be kept |
| if you regenerate the code. |
| <p>To change the icons, you can just change the gifs that are in the <i>icons</i> |
| folder in this plug-in project. |
| <p>In the customized version of the family tree .edit plug-in, the getText |
| methods have been changed in FamilyItemProvider, IndividualItemProvider, FemaleItemProvider |
| and MaleItemProvider. For example, here's the code from IndividualItemProvider: |
| <pre> public String getText(Object object) { |
| Individual individual = (Individual)object; |
| if( individual.getName() == null ) |
| return "Unnamed individual"; |
| return individual.getName(); |
| }</pre> |
| |
| <h2> |
| Trees</h2> |
| The simplest tree view is the one used for the generated editors |
| content outline view and the selection tree view. The content provider |
| for this is <b>org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider</b>, |
| which uses the generated adapter classes from <b>com.ibm.example.familytree.edit</b>. |
| The children of each element are the elements it contains. |
| <p>You can create different tree views by writing your own content provider. |
| However, make sure that you won't have the same element appearing twice |
| in the tree as this will cause problems. The tree viewer assumes that each |
| domain element maps to one tree item. If you need to show referenced elements |
| in a tree, you will have to wrap them. Other structured viewers (tables |
| and lists) behave the same way. |
| <p>In the customized version of the family tree editor, I have changed |
| the input of the content outline view so that the root of the tree is now |
| FamilyTree instead of the resource (file), and changed the root and title |
| of the selection tree view. |
| <p>I have added the inner class ParentAdapterFactoryContentProvider in place of |
| ReverseAdapterFactoryContentProvider. This returns the parents of a child as |
| the tree 'children', resulting in a tree showing parents, grandparents, great-grandparents |
| etc. Here's how the getChildren method is implemented: |
| <pre> public Object [] getChildren(Object object) { |
| Object parent = super.getParent(object); |
| if( parent instanceof Family ){ |
| List parents = new ArrayList(); |
| if( ((Family)parent).getMother() != null ) |
| parents.add( ((Family)parent).getMother() ); |
| if( ((Family)parent).getFather() != null ) |
| parents.add( ((Family)parent).getFather() ); |
| return parents.toArray(); |
| } |
| return new Object[0]; |
| } |
| |
| </pre> |
| |
| <h2> |
| Tables</h2> |
| Table viewers require a content provider and a table label provider. |
| <b>org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider</b> |
| implements the <b>org.eclipse.jface.viewers.ITableLabelProvider</b> interface, |
| but it delegates the real work to the generated adapter classes. Modify |
| these to implement the <b>org.eclipse.emf.edit.provider.ITableItemLabelProvider</b> |
| interface. |
| Then change the constructor of FamilytreeItemProviderAdapterFactory so |
| that it knows it can supply a table item label provider. |
| <P>You will also need to set up the table with the right columns; |
| in the generated editor this is done in the createPages method. |
| <p>The second page of the editor is now a table tree, using the content |
| provider described above. It shows parents of children. I have defined |
| three columns - Parents, Father and Mother. You can expand items in the |
| first column to see parents of parents. |
| <p>I modified IndividualItemProvider so that it implements ITableItemLabelProvider. |
| The second column shows the individuals father, the third column their mother. |
| Here's how the method getColumnText is implemented in IndividualItemProvider: |
| <pre> public String getColumnText(Object o, int index ){ |
| if( index == 0 ){ |
| return getText(o); |
| } |
| else{ |
| Object f = getParent(o); |
| if( f instanceof Family ){ |
| if( index == 1 && ((Family)f).getFather() != null ){ |
| // father |
| return getText(((Family)f).getFather()); |
| } |
| else if( index == 2 && ((Family)f).getMother() != null ){ |
| // mother |
| return getText(((Family)f).getMother()); |
| } |
| } |
| } |
| return "unknown"; |
| }</pre> |
| <p>Heres the customized version of the editor, showing the table tree: |
| <p align="center"> <img SRC="images/customized.JPG"></p> |
| <h2> |
| Menus</h2> |
| The generated ActionBarContributor is responsible for the popup menus, |
| toolbar and menu bar items. The popup menu contents depend only on the |
| selected elements, not the active viewer. |
| <p>The menu items New Child and New Sibling are somewhat confusing in |
| this context, so I have changed the ActionBarContributor to just have the |
| submenu Add New, with menu items Family, Male, Female. |
| <h1> |
| Conclusions</h1> |
| This article has introduced the process of plug-in development using EMF |
| and shown how to start customizing the EMF generated editor code for your |
| own use. By using EMF in your own plug-ins you can benefit from reusing |
| user interface parts that are based on EMF. When you are familiar with |
| the framework, you can quickly build functional new editors and views. |
| <p>For more information about EMF, see the EMF tutorial (in the Eclipse Help for |
| EMF), documentation, and the EMF newsgroup (<a href="news://www.eclipse.org/eclipse.tools.emf">news://www.eclipse.org/eclipse.tools.emf</a>). |
| <p>Java and all Java-based trademarks and logos are trademarks or registered |
| trademarks of Sun Microsystems, Inc. in the United States, other countries, |
| or both. |
| </body> |
| </html> |