Build date: 16-June-2006
Table of Contents
This document addresses people who want either to use Eclipse Modeling Framework in order to create an EMF model, and/or to manipulate them using Kermeta. The use of EMF models in Kermeta is done via the following steps, which some of them are optional. We will detail them in the later sections. So, creating an EMF model consists on :
creating an meta-model in ecore format, following a few constraints that make its instances loadable by Kermeta
creating a model, as an instance of the above meta-model, which we call, as you noticed, EMF model
loading this model and manipulating it with a Kermeta transformation
saving this model, or another model created from scratch with Kermeta.
Important | |
---|---|
Kermeta is an evolving software and despite that we put a lot of attention to this document, it may contain errors (more likely in the code samples). If you find any error or have some information that improves this document, please send it to us using the bugtracker in the forge:http://gforge.inria.fr/tracker/?group_id=32Last check: v0.1.0 |
Tip | |
---|---|
Most of the code presented in this tutorial comes from the FSM sample available on the kermeta web site. Have a try to it for a complete working sample ! |
People who read this document need to have some more or less precise knowledge about either EMOF or ECore metamodels
since ecore is used, people should have a minimal knowledge, as end-users, of Eclipse development environment.
metamodel : we will talk about metamodel and ecore model to design the same thing, e.g the metamodel level. Ecore model is the Eclipse term for a metamodel written in ecore.
instance : in the context of this tutorial, we'll use instance to refer to an instance of the metamodel, i.e an EMF model. Sometimes we will talk about instance-model (an EMF model that is an instance of the metamodel), so, don't get confused.
model object, root class : this term (which correspond to the Model Object in Eclipse words) does not really mean anything, but, at least in the dynamic editor provided by EMF , you can only create instances of classes through a root class that contains the others. A root class is the only class that has no container (so, no “black-diamonded” relation points to it).
containment : this term is important, since you will have to set this property for attributes/references of any class in order to allow to access all the instances of the EMF model through the model object, which is aimed at being the highest-level container (you will see that at the 10th step of section 2.1, p.3, and fig )
The needed environment to create EMF models is the following, for any OS :
Eclipse, preferably the 3.1.1 version
Java 1.5
Ideally, Omondo, that provides a graphical editor of ecore metamodels
Kermeta plugin (remote site for a direct eclipse installation : http://www.kermeta.org/update ), version 0.1.0
EMF modeling framework, version 2.1.0 (remote site : Eclipse update site)
You will find the necessary plugins by using Eclipse installation tool. This can be found through the tool bar menu : Help > Find and install > Search for new features to install > Next buttons
In this tutorial, we have chosen to show you how EMF and loading works with the classical example of finite state machines.
Create a new simple project, call it, for example, MyFirstEMFSamples .
Select in the toolbar menu (on top of Eclipse window) File > New > Other > Example EMF Creation Wizards folder > Ecore Model
give a file name to your metamodel (e.g fsm.ecore), then click on Next button
choose EPackage as the Model Object (the root of your metamodel), and click on the Finish button
If you have Omondo installed, you can create a meta-model using the graphical editor, but in this tutorial, we advise you to use the Sample Ecore Editor (if omondo editor was opened by default, i.e if you see the graphical editor, close it, and reopen your ecore model while right-clicking on it, then select the Open with > Sample Ecore Editor)
if you don't see a tab called Properties, at the bottom (or left, or right) part of your eclipse, open it using the toolbar menuWindow > Show View > Other > Basic folder > Properties;
through this tab, you need to set 2 properties to your EPackage (which is displayed as null for the moment)
its Name : fsm, for example;
its Ns URI : the namespace URI of the ecore model is mandatory to let Kermeta be able to load correctly its potential instances, as well as for the Dynamic creation of instances tool (see section 3.1 p.11). It is stronlgy recommended to set an absolute Eclipse URI (this kind of URI is actually relative to your Eclipse project), e.g platform:/resource/MyFirstEMFSamples/metamodels/fsm.ecore
you can now add children (e.g a class (EClass), a package (EPackage), a datatype (EDataType) in your root (which is fsm EPackage in our example) by right-clicking on it and choosing the New child item. In our example, we will add three classes, which one of them will be the “root class” (model object!); this should not be mandatory, but EMF works best this way. In our example, this Fsm is the root class. So let's create :
a Fsm, for which we will set the Name in the properties window (you don't need to consider the other properties for the moment)
a Transition (idem as Fsm class)
a State
to add operations, attributes, or references on your new classes it is the same philosophy as for adding classes to an EPackage, i.e using New child on each created element.
still through the Properties tab, you will have to set the EContainment property to true on each reference for which you will want to add instances. For example, in our automaton, transition and state references are containments of Fsm class. Thus, we will be able to create, in an EMF model of it, a collection of transitions and states. It will be easier to understand it once you are at the EMF model creation step (section 3, p.11)
to add properties to the attributes, operations, and references, like the upper and lower bounds, their types (EType), you still have to use the Properties tab. The main properties to consider are : ESuperType, EType, Name, Upper Bound, Lower Bound, Containment (for the diamond-ed associations), Ordered, Unique, and EOpposite (opposite property). For the tutorial goals, you can ignore the others.
Lower and upper bound properties : 0, 1, -1 (stands for *) are allowed
don't forget to save your model
Note | |
---|---|
For the primitive types case, like the String, Integer, Boolean, you have to create EAttribute, but not EReferences. For the other types, you must create a EReference. |
At this stage of the tutorial, you should have the following metamodel:
Creating a good metamodel is some time difficult due to limitation of the tools you use. You'll have the best experience with EMF tools and Kermeta if your metamodels follow those rules:
Create an element that will contain directly or indirectly all the other elements.
The reflexive editor and the editor generated by EMF allow to create only one root element and then, from this element, create contained element.
This problem occurs only for model element creation from the editors. The editors correctly display models from metamodels that doesn't follow this rule if you are able to create such models by another mean. Kermeta is not affected by this constraint.
You can find more documentation about EMF at the following links :
More generally, you can find most of the documentation in the eclipse website.
EMF tools are not the only way to create ecore metamodels. Any tool that can manipulate ecore can do the same. Here is a small list of tools that can be used to create your metamodel:
Omondo / Eclipse UML has a nice graphical editor for ecore models.You can even generate the EMF editor directly from this tool.
Kermeta: You can write your metamodel with kermeta and then translate it into ecore using the kermeta2ecore function.
Tip | |
---|---|
You can use this ecore import/export function and the Omondo editor in order to display graphically your kermeta classes. It will act as a basic manual roundtrip editor. |
This is the most simple way to create an instance of your metamodel. You right click on the root class/model object of you metamodel (in our example, it is the Fsm class) : actually all your classes are only available, for creation, through this root class (remember, the containment property).
Tip | |
---|---|
You should favour this solution if your metamodel is relatively stable, as it allows you to customize the generated editor to match your metamodel specificities. (see the end of this article: http://www.eclipse.org/articles/Article-Using%20EMF/using-emf.html ) |
This is the most ergonomic – but longest – way to create an instance of your metamodel. We will not detail the process here, but only give you the main lines:
once your metamodel is created, you can create a model for model generation, called genmodel :
File > New > Other > Eclipse Modeling Framework folder > EMF Models
choose a name for your genmodel (fsm.genmodel is ok)
select Load from an EMF core model button, and find your metamodel (fsm.ecore)
select the unique package fsm
you need to change, in the Properties tab of your genmodel, the model directory, in order to avoid weird behavior (particularly if the project you are working in was not set as a “Java project”) : please change the property called Model Directory (in the Model folder), to /MyFirstEMFSamples.model/src, so that the EMF source code is generated in a new empty project that will exclusively contain this source code.
right-click on the root node of your fsm.genmodel, and choose the Generate all item.
To be able to use the generated reflexive editor, you have to launch a new runtime workbench, through the tool bar menu:
Run > Run As > Run-time Workbench (in eclipse 3.0.2)
or Run > Run... > Eclipse application item in the right part > New button > Apply button > Run button at the bottom (eclipse 3.1)
a new eclipse application is launched, so now you can create a new simple project (e.g called MyFirstEMFInstances), and select File > New > Other > Example EMF Creation Wizards folder > Fsm Model
now, to create an EMF model, you have to follow the same principles as the creation of an ecore model. So, you can report to the metamodel creation steps, section 2.1, p.3, and adapt them (for example, the model object, which was EPackage in the metamodel creation, becomes Fsm in the EMF model creation)
as you work in another Eclipse environment, you will probably want to copy the models that you created this way in your initial project (the one named MyFirstEMFSamples). Simply do it.
To load your first kermeta program, you will just have to copy the code provided in the following chapters, following carefully the suggested instructions. Readers who want to directly load their own models should directly go to the section 4.5, p.15 and copy the given template.
The persistence library is inspired from the resource manager of EMF models. There is a repository (called EMFRepository), that is aimed at containing a set of resources (the EMFResources). Each resource contains a reference called instances, that contains all the root classes (usually you only have one root class) of the loaded model. So, the procedure of creation of a resource that will handle your EMF models is the following (code exammple is provided in next sections) :
instanciate an EMFRepository
create a new EMF resource in this repository
load this resource
get the instances, i.e the root class(es). When you have them, you can access all the other instances through accessing the root class(es) properties.
As a reminder, here is the common skeleton of a kermeta program, inside which you will add any library that is necessary to load and save the fsm samples.
@mainClass "fsm_package::Main" @mainOperation "main" package fsm_package; require kermeta require "../metamodels/fsm.ecore" using kermeta::persistence // <- used to load and save EMF models. using kermeta::standard class Main { operation main() : Void is do // TODO: implement 'main' operation end }
Here, we will load one of the Fsm models that we previously created:
operation main() : Void is do // Input fsm var fsm1 : fsm::Fsm // Create the repository, then the resource var repository : EMFRepository init EMFRepository.new var resource : EMFResource resource ?= repository.createResource("../models/Fsm_dyn_sample1.xmi", "../metamodels/fsm.ecore") resource.load // Load the fsm (we get the instance) fsm1 ?= resource.instances.one // Check that the fsm was correctly loaded fsm1.state.each { s | stdio.writeln("-> "+s.name) } fsm1.transition.each { t | stdio.writeln( t.source.name " -- " +s.target.name ) } end
Now, you want to modify your model using Kermeta, and then to save it. The procedure is very simple : do your manipulation as if your loaded fsm model is a Kermeta model (which is, in effect, the case!), and then, simply call a save method on the handling resource. Thus, you can add the following code at the end of the main operation defined in the above section :
var newstate : fsm::State init fsm::State.new newstate.name := "s_new"fsm1.state.add(newstate) // save fsm1 resource.save()
You can also save your model in a new file instead of overwriting the initial one by using save()
:(we just replace the last line of above code (resource.save()
) into this one:
resource.saveWithNewURI("../models/modified_dyn_sample1.xmi")
For this purpose, you will only have to do one specific instruction, that is, add the Fsm root class created from scratch to the destination resource. The following code chunk creates a simple EMF model with 2 states (named “foo”, and “bar”), and 2 transitions. Then saving it consists on adding the root class (i.e the model object) stored in the variable fsm2
in the instances of the resource .
var another_resource : EMFResource another_resource ?= repository.createResource( "../models/Fsm_scratch_sample.xmi", "../metamodels/fsm.ecore") var fsm2 : fsm::Fsm init fsm::Fsm.new var s0 : fsm::State init fsm::State.new var s1 : fsm::State init fsm::State.new var t01 : fsm::Transition init fsm::Transition.new var t11 : fsm::Transition init fsm::Transition.new s0.name := "foo" s1.name := "bar" t01.source := s0 t01.target := s1 t11.source := s1 t11.target := s1 fsm2.state.add(s0) fsm2.state.add(s1) fsm2.transition.add(t01) fsm2.transition.add(t11) // save the from-scratch model! another_resource.instances.add(fsm2) another_resource.save()
You should have the following result (viewed with the reflexive editor):
To load your own models, you can simply fill in the short template code (replace the <words>) given below. Note that we can see that the term model object is appropriate, (better than root class!) : loading a model consists on getting the root class, from which, thanks to the containment property (see section 1.2, p.2), we access all the contained instances.
@mainClass "fsm_package::Main" @mainOperation "main" package fsm_package; require kermeta require "<relative_path_of_the_metamodel>" // NOTE : same as param of createResource using kermeta::persistence using kermeta::standard class Main { operation main() : Void is do // Variable for your input EMF model var <my_model_object> : <type_of_my_model> // Create the repository, then the resource var <my_rep> : EMFRepository init EMFRepository.new var <my_resource> : EMFResource <my_resource> ?= repository.createResource( "<relative_path_of_my_model_to_load>", "<relative_path_of_the_metamodel>") <my_resource>.load // Load the emf model - get the root class <my_model_object> ?= resource.instances.one // You can now browse your model through its attributes/references <my_model_object>.<an_attribute_of_it>.each { o | stdio.writeln("-> "+o.toString) } ) // Save your model in another file <my_resource>.saveWithNewUri("<relative_path_of_a_file_where_to_save_model>") end }
Kermeta allows you to add behavior to a metamodel and obviously you'll want to load models conformant to this metamodel.
The following section explain one of the simpliest way to do that. This is a very small variation on the code presented in the previous sections.
Actually, this is based on kermeta ability to “require” class definition written in several formats. Currently supported formats are: (version v0.0.16)
kmt files(kermeta textual syntax)
km files(kermeta model in xmi2.0)
ecore files (ecore model in xmi2.0)
emfatic files (textual syntax for ecore developped by IBM
Using the transformations Kermeta2Ecore and Ecore2Kermeta, you can obtain two versions of a metamodel. One in ecore, in in kermeta. From a structural point of view, they will be equivalent and compatible in kermeta.
Then, these two syntaxes are structurally equivalent.
Require "fsm.kmt" // if you use this one, you'll have the FSM behavior
is equivalent to
require "fsm.ecore" // if you use this one, you won't be able to use the FSM behavior
Tip | |
---|---|
If you have generated .the ecore from a kmt that defines a behavior, this ecore will also contain the behavior. |
To load or save a model you will continue to use the ecore version so EMF will know how to serialize/deserialize the models.
var my_resource : EMFResource init repository.createResource( "./my_fsm_usermodel.fsm", "./fsm.ecore")
The kermeta version of the metamodel will be used to specify the behavior, the ecore version will be used by EMF for the persistency aspects.
Note | |
---|---|
Kermeta2Ecore and Ecore2Kermeta transformations are available in the workbench (right click on an ecore or a kermeta file) |