What Every Eclipse Developer Should Know About Emf: by Jonas Helming and Maximilian Koegel Eclipsesource Munich
What Every Eclipse Developer Should Know About Emf: by Jonas Helming and Maximilian Koegel Eclipsesource Munich
What every Eclipse Developer should
know about EMF
by Jonas Helming and Maximilian Koegel
EclipseSource Munich
Contact Details:
[email protected]
Email:
Website:
http://eclipsesource.com/munich
Phone: +49 89 21 555 301
This tutorial is also available as a more comprehensive
EMF
training
.
Abstract
This tutorial is an introduction to EMF and explains the basics of EMF. We start by showing
you how to build a very simple datacentric application, including the UI, based on EMF. We
explain how to define a model in EMF and generate code from it. We explore the API of the
generated code, that is, how to create, navigate and modify model instances.
Next we demonstrate how to build a UI based on this model using databinding. For our
example, we build an application to manage a bowling league, including matches and
players. Later on in the tutorial, we explore the advantages of using AdapterFactories and
briefly look at data management in EMF. We also include a few pointers on the most
important addon technologies for EMF. If you are interested in getting fast results building
an application based on EMF, maybe EMF Forms or
EMF Client Platform is also a good
starting point for you, see
this tutorial
.
Installation Requirements: To work through the examples, you’ll need to download and
install a fresh version of the
Eclipse Modeling Tools from the
Eclipse Download Page.
Page 1 What Every Eclipse Developer Should Know about EMFCopyright 20112015 EclipseSource
Introduction
To answer the question, “What is EMF?”, we’ll borrow the description from the EMF website:
“The EMF project is a modeling framework and
code generation facility for building
tools and other applications based on a structured data model . From a model
specification described in XMI, EMF provides tools and runtime support to produce a
set of
Java classes for the model, along with a set of
adapter classes that enable
viewing and commandbased editing of the model, and a
basic editor .”
Source:
http://www.eclipse.org/emf
It is worth mentioning that in addition to being a successful modeling framework, EMF has
also been a stable standard for many other modeling technologies. We recommend using
EMF for any structured data model you want to create in Eclipse, especially if it is stored,
displayed and modified in UIs.
The basic EMF workflow is very pragmatic; a model is created and defined in the Ecore
format, which is basically a subset of UML Class diagrams. From an Ecore model, you can
generate Java code.
Later in this tutorial we will have two running instances of Eclipse. In the first instance, called
the “IDE”, we will define the model and generate code from it. The second instance, called
the “Runtime”, will be started from the IDE and will contain instances of the generated
model.
Page 2 What Every Eclipse Developer Should Know about EMFCopyright 20112015 EclipseSource
Page 3 What Every Eclipse Developer Should Know about EMFCopyright 20112015 EclipseSource
Example Model
In this tutorial we will create an example model for managing a bowling league and its
tournaments. A League contains an arbitrary number of Players. A Tournament consists of
an arbitrary number of Matchups. Each Matchup always contains two Games. A Game is a
list of frames (the score) and is assigned to a certain Player. Finally, a Tournament has an
Enumeration that determines the type of Tournament.
In the next section, we will show how to create and generate code from this model.
Page 4 What Every Eclipse Developer Should Know about EMFCopyright 20112015 EclipseSource
Modeling
We will create our example model in EMF to generate the entity classes for our application.
The first step is to create an empty modeling project in your workspace. In your running IDE
select “File” from the toolbar menu → “New” → “Other...” and choose “Empty EMF Project”.
Click “Next”, enter a name for the project, e.g., “org.eclipse.example.bowlingmodel”, and hit
“Finish”:
Page 5 What Every Eclipse Developer Should Know about EMFCopyright 20112015 EclipseSource
The essential part of the modeling project is the model itself, defined in the format “Ecore”.
Please right click the model folder in your new modeling project → “New” → “Other...” →
“Ecore Model” → “Next” and give the ecore file the name “bowling.ecore”.
Page 6 What Every Eclipse Developer Should Know about EMFCopyright 20112015 EclipseSource
Click “Finish” to create the model. It will open in the default Ecore editor, which allows the
definition of Ecore models in a treebased view. There are several additional options for
defining Ecore models, including graphical modeling, textual modeling, Java annotations and
importing from UML tools. We will stick to the default editor in this tutorial and later, briefly
demonstrate the graphical editor for Ecore.
In the Ecore editor tree, you can create and delete model elements as well as modify the
structure of your model via drag and drop. Properties of model elements can be modified in
a second view, which opens up on doubleclick or rightclick → “Show Properties View”.
You’ll need to give thepackage of your new model a name and an URI. This will be done in
the properties view. The URI is used to identify the model later on. Name the package
“bowling”, set the Ns Prefix to “org.eclipse.example.bowling” and the Ns URI to
”http://org/eclipse/example/bowling”.
Now we can define our model elements as children of the root package. Create a new
EClass by right clicking on the bowling package → “New Child” → “EClass” and set the
name to Player in the properties view of the newly created EClass
Page 7 What Every Eclipse Developer Should Know about EMFCopyright 20112015 EclipseSource
From the context menu of an EClass, you can add EAttributes and EReferences as children.
Create an EAttribute in the Player EClass and open the Property view for it. The properties
of an EAttribute define its name, its data type and other properties, which we will cover later
in the tutorial. Set the name to “name” and assign the EType “EString” (java.lang.string).
Repeat this step and add a second EAttribute named “dateOfBirth” of type “EDate”. The
convention we’ll use here is that all class names start with an uppercase letter, attributes and
references start with a lowercase letter.
EMF models usually build up a structured hierarchy, that is, model element instances. For
Page 8 What Every Eclipse Developer Should Know about EMFCopyright 20112015 EclipseSource
example, a Player is contained in a specific container object. This provides a tree structure,
which is useful for navigation and serialization (e.g. XML). This tree structure is often
referred to as a containment tree. In our model, Players are contained in a League. It is
important to note that this also implies that every Player is referenced by exactly one
League, and thus cannot be part of more than one League. EMF will automatically make
sure that a player is not contained in more than one league. If you add a player to a second
league, its reference to the original league vanishes.
Create a second EClass and name it “League”. To identify the League, also create an
EString attribute called “name”. The next step is to create an EReference between League
and Player by right clicking on the League model element. Name the reference “players”. Set
the EType of the reference to “Player”. Since a League can contain an arbitrary number of
Players, set the upper bound to “1”, the equivalent of “many”. Finally, set the property
Containment to “true”, defining the EReference to be a containment reference.
Page 9 What Every Eclipse Developer Should Know about EMFCopyright 20112015 EclipseSource
We can already generate code from this first model iteration, which will be shown in the next
section. EMF can also generate an example editor. With this editor you can create instances
of the generated model, in our case, instances of Leagues and Players. This allows us to do
initial testing on the model by creating instances of it. Then we can further refine and add
more EAttributes and EReferences in a second iteration that will complete the model.
Code Generation
In this step, we will generate the entities from the Ecore file we have created. Note that if you
need to change your model, you will be able to regenerate the entities again. EMF can deal
with simple changes like adding model elements or EAttributes. If you have complex
changes, like moving an attribute to another class, you will have to migrate existing
instances of the model. This is supported by the EDAPT framework. (see
http://www.eclipse.org/edapt/ )
To generate entities, we first have to create a generator model. This allows you to configure
properties for the code generation that are not part of the model itself. For example, source
code is generated for the plugin and subfolder as well.
Right click the model folder in the project → “New” → “Other...” → “EMF Generator Model”
→ “Next” and enter bowling.genmodel as the file name. Proceed to the next page and select
Page 10 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
“Ecore model” as the model importer. After clicking “Next”, select “Browse Workspace...” and
select our previously created bowling.ecore. Go the next wizard page and select “Finish”.
Page 11 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
In the root node of the generator model, you can set the properties for generating code. In
Page 12 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
the tree of the generator model, we can set properties for every generated entity. For the first
code generation, we’ll use the default settings. Based on the generator model, we can now
generate the source code. EMF allows you to generate a maximum of four different plugins
for a defined model:
● Model : The model contains all entities, packages and factories to create instances of
the model.
● Edit : The edit plugin contains providers to display a model in a UI. For example, the
providers offer a label for every model element, which can be used to display an
entity showing an icon and a name.
● Editor : The editor plugin is a generated example editor to create and modify
instances of a model.
● Test : The test plugin contains templates to write tests for a model.
To generate the plugins, rightclick on the root node of the generator model and select the
plugin. For our tutorial, please select “generate all”.
Before we look at the generated code, let’s start the application and create an entity of our
model. Right click on the plugin containing the ecore file and select “Debug as → Eclipse
Application”. This will start a new runtime Eclipse.
Then, in the runtime, create a new empty project (Toolbar menu → “File” → “New” →
”Other...” → “General” → “Project”) named bowlinginstance.
Page 13 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
Right click the created project → “New” → “Other...” → “Example EMF Model Creation
Wizards” → “Bowling Model” → “Next” and enter league.bowling as the name. This file will
contain a serialized version of our model instance.
Page 14 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
Select League as the model object. This sets the root object of the model instance we are
about to create.
The generated editor for model instances works similarly to the Ecore editor. Model element
instances can be created via a rightclick and EAttributes can be modified in the properties
view. Please give the League a name and create two Players. On save, all created instances
Page 15 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
are serialized in the XMI file “league.bowling”.
Model Refinement
Let’s switch back to our IDE Eclipse environment, complete the model and regenerate the
source code. In this second model iteration, we will add different type of EReferences as well
as EEnums and MultiEAttributes. First, add the following classes to the bowling model:
● Tournament
● Matchup
● Game
These classes model the results of bowling tournaments and build up a second tree in our
model. Therefore, we add containment EReferences from Tournament to Matchup and from
Matchup to Game. Following the bowling rules, a Matchup consists of two Games (each
from one Player). We model this by setting the upper bound and lower bound of the
EReference “games” of the EClass Matchup to “2”.
Page 16 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
We defined the EReference between Matchup and Game as bidirectional. This means that
the reference can be navigated from both ends. Therefore we have to create a second
EReference from Game to Matchup and bind both EReferences. EMF will take care of the
bidirectional synchronization. In other words, adding a Matchup to a Game will automatically
add the Game to the Matchup.
Please add an EReference to Game called “matchup” with the EType “Matchup”. By setting
the EOpposite to the EReference “games”, both EReferences are coupled bidirectionally.
Note that the property “Container” will automatically be set to True.
Page 17 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
The next step is to add a crossEReference. In contrast to containment EReferences,
crossreferenced model elements do not contain each other. In our model, we add a
crossreferencing EReference from Game to Player named “player”. Set both container and
containment properties to “false”. An arbitrary number of games can be assigned to a Player
now and the Player is still contained in a League.
As a final mandatory step, we will create an EEnumeration for the type of Tournament. A
Tournament can be of type “Pro” and “Amateur” in our model. Please create an EEnum by
rightclicking on the root bowling model package, in the same way we created a class. Add
two EEnum Literals to this EEnum.
Then, add an EAttribute to the EClass Tournament, name it “type” and set the EType to
“TournamentType”.
Page 18 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
The extended example model contains more EAttributes and EReferences to be added
including all basic types and some special cases as the MultiInteger EAttribute in
Tournament. If you’d like, you can also model the following features:
Player
● height: EDouble
● isProfessional: EBoolean
Game
● frames: EInt, UpperBound = 10
After applying complex changes to the model it is always a good idea to validate it with a
rightclick on the model root in the Ecore editor. Let’s do something wrong in the model and
set the lower bound of the EAttribute “games” (in Matchup) to 3. As the upper bound is 2,
this model doesn’t make too much sense. This will be detected by the model validation
something that is impossible in plain Java code.
After this model refinement, we will regenerate the code to reflect our changes. Start the
runtime Application again and create a second model “tournament”. Add a Matchup and two
Games. To assign the Games to Players you will have to load the “league” model created
earlier. Select “Load Resource” from the menu “Bowling Editor” and select the first model
file. Now link the Games to the Players in the properties view.
Why is This Better than Writing POJOs?
You might ask, “Why should I use EMF instead of creating the model by writing plain
POJOs?” Without considering benefits like the generated editor for rapid testing and all the
additional frameworks available for EMF, let’s look at two very simple and exemplary
benefits.
Page 19 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
Before we look at the generated code (we will do that in a minute), let’s consider the amount
of code we have just produced. The Eclipse metrics plugin tells us that we have generated
over 1,000 LOC, while only 150 are part of utility classes. Even very simple code is
considered to be worth $1 per LOC. So, we have earned $1,000 just by clicking some
buttons ;)
In the next sections, we’ll explore the EMF API for the code we have generated.
Page 20 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
EMF API
In this part of the tutorial, we will explore EMF’s API, including the generated code, as well
as EMF’s utility classes. Let’s have a look at the generated code first.
In the model plugin from our tutorial org.eclipse.example.bowling you will find interfaces and
implementations for all of the model’s entities. A look at the outline of an entity’s interface
reveals that it contains getters and setters for the attributes we have defined in the model as
well as getters for the references. All entities of the generated EMF model are subclasses of
EObject. EObject contains basic functionality – for example, a change notification
mechanism.
The model plugin contains factories to create model element entities. Note that the
constructor of EObjects is usually not public. Please also note that factories are used by
many frameworks for their functionality, e.g., deserialization. Changing these methods
successfully requires some careful planning. Let’s use the factories to programmatically
create some entities and use their APIs to modify them. We will use the pregenerated test
plugin to run this example code. If you open the plugin,
org.eclipse.example.bowlingmodel.test, you will find a generated test class for all of the
entities of your model. By adding methods starting with “test” you can create single test
cases. The test cases can be started with a rightclick on the test class => “Debug As” =>
“JUnit Test”. Please note that we will not really “test” our model. In this context test cases are
just a very simple way of exploring and using the API of the generated classes.
In this very simple example, we’ll use the BowlingFactory to create a Matchup and a Game,
adding a reference to the Matchup and checking the bidirectional update on the Game.
public void
testMatchupGameRef() {
eINSTANCE
Matchup matchup = BowlingFactory. .createMatchup();
eINSTANCE
Game game = BowlingFactory. .createGame();
matchup.getGames().add(game);
assertEquals(game.getMatchup(), matchup);
}
The super class EObjects offers many methods to access an entity in a more generic way.
For example, we will test the containment between Matchup and Game by accessing the
EContainer instead of the getMatchup() method.
public void
testMatchupGameRef() {
Page 21 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
eINSTANCE
Matchup matchup = BowlingFactory. .createMatchup();
eINSTANCE
Game game = BowlingFactory. .createGame();
matchup.getGames().add(game);
assertEquals(game.eContainer(), matchup);
}
EObjects offer reflective access to their attributes using the methods eSet() and eGet(). This
can be useful in modifying an entity in a generic way.
public void
testReflection() {
eINSTANCE
EObject eObject = BowlingFactory. .createPlayer();
eINSTANCE
eObject.eSet(BowlingPackage. .getPlayer_Name(),
"Jonas"
);
Player player = (Player) eObject;
assertEquals(
"Jonas"
, player.getName());
}
Information about the available EAttributes and EReferences, as well as all additional
concepts we have modeled before, can be accessed either through the EClass or through
the EPackage. The following test checks whether the EReference of League is a multiplicity
greater than one.
public void
testReflectiveInformation() {
eINSTANCE
League league = BowlingFactory. .createLeague();
assertTrue(league.eClass().getEAllReferences().get(0).isMany());
eINSTANCE
assertTrue(BowlingPackage. .getLeague_Players().isMany());
}
EMF also supports the validation of model instances. For example, we can validate the
model’s constraint that a matchup must always consist of two games.
public void
testValidation() {
eINSTANCE
Matchup matchup = BowlingFactory. .createMatchup();
eINSTANCE
matchup.getGames().add(BowlingFactory. .createGame());
INSTANCE
Diagnostic validate = Diagnostician. .validate(matchup);
ERROR
assertEquals(Diagnostic. , validate.getSeverity());
}
Finally, EMF provides many utility classes. A very important one is EcoreUtil. It is worthwhile
browsing through the available methods of EcoreUtil. We’ll use the copy method to create a
copy of an EObject.
Page 22 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
public void
testCopy() {
eINSTANCE
Player player = BowlingFactory. .createPlayer();
player.setName(
"Jonas"
);
Player copy = EcoreUtil.copy(player);
assertNotSame(player, copy);
assertEquals(player.getName(), copy.getName());
}
Page 23 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
Import Intermediate Sample Solution
Before we continue with the tutorial, please import the intermediate sample solution, which
can be downloaded
here
.
Switch to an empty workspace (File → Switch Workspace) and select “Import” → “General”
→ “Existing Projects into Workspace”. Select “EMFTutorialIntermediateSolution.zip” and
import all projects.
Page 24 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
AdapterFactories
For the next sections of the tutorial, it is important to understand the concept of
AdapterFactories. We will give a basic introduction. More advanced concepts are also
described here
.
The basic function of AdapterFactories is to provide you with the interface you need for a
certain purpose such as an ILabelProvider needed in the UI. EMF generates a lot of these
classes for you. To retrieve the right class, you can use an AdapterFactory implementation
of the interface you need, e.g., an AdapterFactoryLabelProvider. The
AdapterFactoryLabelProvider will retrieve the generated LabelProviders for all EObjects
using an AdapterFactory.
Page 25 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
EMF Data Management
In the previous sections we have shown how to generate a structured data model with EMF.
In a typical application, these data models have to be stored and likely also versioned and
distributed. There are a couple of frameworks that support different use cases.
By default EMF provides the ability to serialize EObjects to XMI files. In the following
example, we will load EObjects from a file and save them afterwards. EMF also offers
commands to make modifications to the model. Commands can be easily undone. In the
example, we will load an XMI file containing a Tournament. We can add new Matchups to
that Tournament and undo these changes. When we’re finished, we can save the changes
back to the file.
For the tutorial, we have prepared an example dialog in the plugin
org.eclipse.example.bowling.tutorial, which has been imported from the sample solution. You
can open this dialog by rightclicking a file containing instances of a bowling model and
select “Tutorial” → ”Open Tournament Example Dialog”. After implementing the next two
sections of the tutorial, it will look like this:
In the subclass ExampleTournamentDialog, there are empty method stubs to be
implemented in this tutorial. Just a note here that for the purposes of the tutorial we have
focused on simplicity over perfect design. Also, everything that is not relevant for the tutorial
is implemented in an abstract base class called AbstractTournamentExampleDialog.
Now you’ll need to open the class ExampleTournamentDialog. We will implement the
loadContent method, which is triggered by opening the example view. The purpose of this
method is to get a Tournament from the file that is then displayed in the example view. To
keep it simple, we assume that the file contains a Tournament and this Tournament is the
first element in the file. You can easily create a file like this with the generated example
editor.
First, we create an editing domain. An editing domain manages a set of interrelated models
Page 26 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
and the commands that are run to modify them. For example, it contains the stack of all
former commands. An editing domain can create a resource, which is a container for storing
EObjects. Resources can be saved and loaded and contents can be added to them. In the
example, we get the first EObject in the resource, assume it is a Tournament and make it a
member of our superclass.
@Override
protected void
loadContent(IFile file) throws
IOException {
// Load Tournament from file and set it with setTournament
AdapterFactoryEditingDomain domain = new
AdapterFactoryEditingDomain(
getAdapterFactory(),
new BasicCommandStack());
resource
= domain.createResource(file.getFullPath().toString());
resource
.load(
null
);
EObject eObject =
resource
.getContents().get(0);
setTournament((Tournament) eObject);
}
After loading the content, we will implement a save. This will be triggered by pressing OK in
the dialog and will serialize the model and apply all changes to the file.
@Override
protected void
save()
throws
IOException {
// save changes in the file
resource
.save(
null
);
}
Now we want to implement the addition of a Matchup to a Tournament. We will use a
command for this. First we create a Matchup using the appropriate factory. The factory, by
convention, has the same name as the base package of the model. Then we create a
command which adds the newly created Matchup to the Tournament that has been loaded
from the resource in the previous step. Finally, we run the command on the command stack
of the editing domain.
@Override
protected void
addMatchup() {
// add a new Matchup using a Command
eINSTANCE
Matchup matchup = BowlingFactory. .createMatchup();
EditingDomain editingDomain = AdapterFactoryEditingDomain
.getEditingDomainFor(getTournament());
Command command = AddCommand.create(editingDomain, getTournament(),
eINSTANCE
BowlingPackage. .getTournament_Matchups(),
matchup);
editingDomain.getCommandStack().execute(command);
}
Page 27 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
At this point, the changes will not be reflected in the dialog’s UI, but we will implement the
code in the next section of the tutorial.
The next step is to implement undo. To undo the last command, all you’ll need to do is to
call undo on the command stack of the editing domain.
@Override
protected void
undo() {
// Undo the last change
AdapterFactoryEditingDomain
.getEditingDomainFor(getTournament())
.getCommandStack().undo();
}
Now, start the bowling application and create an XMI file with the example editor. It should
contain a Tournament and several Matchups and Games. Right click on the file and select
“Tutorial” → ”Open Example Tournament View”. In this view, you can add new Tournaments,
undo this operation and save by clicking on “OK”. You can validate the result by opening the
file in the Ecore editor. Please note again that the UI of the View will not be updated yet, but
we will initialize the UI in the next step of the tutorial.
Additional Persistence Frameworks
There are several frameworks for storing and versioning EMF model instances. Here are
three that we can recommend:
● EMFStore (Model Repository)
● CDO (Model Repository)
● Teneo (Database Backend)
Page 28 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
EMFStore
Merge Dialog
EMF UI
In this section we will show two examples of how EMF supports in developing UIs and
thereby fill the example view with two basic UI elements. More concretely, we will show, how
to attach listeners to EMF model instances and how to create a tree viewer based on EMF.
Please note, this is only the tip of the iceberg. EMF offers extensive support for creating
different kinds of UIs based on a given data model. As an example, it supports databinding
to bind UI elements to the data of a model instance. Furthermore, there are several
frameworks supporting UI development, which are summarized at the end of this section.
For instance, if you want to create a formbased UI allowing you to show and enter attributes
and references from your data model, such as shown below, you should take a look at EMF
Forms .
EMF Listener
Page 29 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
In this section, we will bind the Label to the top showing the number of Matchups in the
opened Tournament to the model. We will use the notification mechanism to update the
Label whenever the number of Matchups changes. Second, we will fill the TreeViewer with a
list of the Matchups and display their Games as children. To update, the Label we will
register a listener on the Tournament EObject, which is opened in the view. This listener will
always be notified by the EMF runtime if there is a change in the Tournament EObject.
@Override
protected void
initializeListener() {
// initialize a listener for the Label displaying the number of Matchups
numberOfMatchupListener
= new NumberofMatchupListener();
getTournament().eAdapters().add(
numberOfMatchupListener
);
}
In the second step, we will implement the listener itself. In the notify method, we check first
whether the change was on the EReference to Matchups and consequently influenced the
number of Matchups. If this is the case, we update the Label via the
updateNumberOfMatchups method (implemented in the AbstractTournamentExampleView).
private final class NumberofMatchupListener
extends
AdapterImpl {
// Implement a listener to update the Label. Call updateNumberOfMatchups
@Override
public void
notifyChanged(Notification msg) {
if (msg.getFeature().equals(
eINSTANCE
BowlingPackage. .getTournament_Matchups())) {
updateNumberOfMatchups();
}
super
.notifyChanged(msg);
}
}
This is how you would manually implement listeners. To create UIs with bidirectional
updates between UI elements and datamodels, we recommend using data binding that is
already available for EMF. In Eclipse databinding, you can bind a certain UI element to a
certain EAttribute or EReference, and it will take care of bidirectional updates. To implement
formbased UIs, you should also have a look at EMF Forms .
Tree Viewer
Next, we will initialize the TreeViewer to display the Matchups of the current Tournament and
their Games as children. A TreeViewer needs three things to be initialized: the
ContentProvider, the LabelProvider and an input. The ContentProvider defines the structure
Page 30 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
of the Tree by providing the method getChildren(). The LabelProvider is called to get an icon
and the text to be displayed for one node. The input of a TreeViewer is the invisible root
element of the Tree. The elements displayed in the root of the tree are the children of that
element. In our case, the input is the Tournament.
ContentProvider and especially LabelProvider usually depend on a certain EClass. EMF
generates providers for several purposes including Content and LabelProvider. We will use
the AdapterFactory concept explained previously to retrieve the right provider for every
element. Finally, we set the Input to the Tournament that is currently open.
@Override
protected void
initializeTreeviewer(TreeViewer treeViewer) {
// initialize a TreeViewer to show the Matchups
// and Games of the opened Tournament
AdapterFactoryLabelProvider labelProvider =
new
AdapterFactoryLabelProvider(
getAdapterFactory());
AdapterFactoryContentProvider contentProvider =
new
AdapterFactoryContentProvider(
getAdapterFactory());
treeViewer.setLabelProvider(labelProvider);
treeViewer.setContentProvider(contentProvider);
treeViewer.setInput(getTournament());
}
To test the UI features just implemented, you’ll need to restart the bowling example
application. To modify the appearance of a Label you can simply modify the ItemProvider of
the respective class. Let’s modify the LabelProvider for Matchup. To modify the appearance
of EObjects in the TreeViewer, you can adapt the generated ItemProvider
MatchupItemProvider. We will show the number of Games contained in a Matchup Game in
the example. Mark the method as “generated NOT” to prevent it from being overwritten
during the next generation.
Page 31 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
/**
* This returns the label text for the adapted class.
* <! beginuserdoc
* > <! enduserdoc >
* @
generated
NOT
*/
@Override
public
String getText(Object object) {
if (object
instanceof Matchup) {
EList<Game> games = ((Matchup) object).getGames();
if
(games !=
null) {
return "Matchup, Games: "
+ games.size();
}
}
return
getString(
"_UI_Matchup_type");
}
In the running application, the new LabelProvider is displayed in the Tournament Example
view as well as in the Ecore Editor:
As a last step, you should remove all listeners when closing the view. Note that
LabelProvider and ContentProvider are registered listeners on the model, so you should
delete them as well.
If you want to have a look at the final sample solution, please import the projects from
this
link
.
Additional UI Frameworks
There are several frameworks for displaying data from an EMF model instance. If you want
to create formbased UIs, maybe even for different UI platforms, such as in the screenshot
below, you should definitely have a look at
EMF Forms .
Page 32 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
If you want to create an application similar to the screenshot below, you should definitely
have a look at the
EMF Client Platform (
Tutorial
).
EMF Client Platform Navigator and Editor
Additional frameworks that are worthwhile having a look at for creating UIs are:
● Graphiti
(Graphical Editor)
● Graphical Modeling Framework (Graphical Editor)
● Extended Editing Framework
(Advanced Property View)
Additional EMFbased Technologies
In this last section of the tutorial we’d like to give you our short
Page 33 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource
[email protected] list of additional EMFbased technologies for you to explore:
● EMF Compare for comparing models
● EDAPT for migrating models
● EMF IncQuery for querying models
● XText for textual modeling (DSLs)
Conclusion
We hope you found this tutorial helpful. If you have feedback or questions, please feel free to
contact us at
[email protected] . Updates of this tutorial will become available
here
.
Page 34 What Every Eclipse Developer Should Know about EMF Copyright 20112015 EclipseSource