How to create an EMF model and use it in Kermeta

Zoé Drey

Didier Vojtisek

Build date: 16-June-2006


Table of Contents

1. Introduction
1.1. Required knowledge
1.2. Terminology and format used in this tutorial
1.3. Required environment
2. Create a meta-model for Kermeta programs
2.1. Step by step
2.2. Resulting metamodel
2.3. EMF Metamodel creation tips
2.4. External documentation
2.5. Alternative ways to create a metamodel
3. Create an EMF model from your metamodel
3.1. With the dynamic instance creation tool
3.2. Using a reflexive editor
3.2.1. Generate the editor
3.2.2. Use the editor
4. Manipulate EMF models with Kermeta
4.1. Preparing a Kermeta program
4.1.1. The persistence library
4.1.2. Your first Kermeta program using persistence
4.2. Load an EMF model with Kermeta
4.3. Modify and save an EMF model with Kermeta
4.4. Create a model in Kermeta, and save it as an EMF model
4.5. A template for a complete kermeta program
5. Metamodel with behavior and persistency

Chapter 1. Introduction

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 :

  1. creating an meta-model in ecore format, following a few constraints that make its instances loadable by Kermeta

  2. creating a model, as an instance of the above meta-model, which we call, as you noticed, EMF model

  3. loading this model and manipulating it with a Kermeta transformation

  4. saving this model, or another model created from scratch with Kermeta.

[Important]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]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 !

1.1. Required knowledge

  1. People who read this document need to have some more or less precise knowledge about either EMOF or ECore metamodels

  2. since ecore is used, people should have a minimal knowledge, as end-users, of Eclipse development environment.

1.2. Terminology and format used in this tutorial

  1. 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.

  2. 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.

  3. 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).

  4. 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 )

1.3. Required environment

The needed environment to create EMF models is the following, for any OS :

  1. Eclipse, preferably the 3.1.1 version

  2. Java 1.5

  3. Ideally, Omondo, that provides a graphical editor of ecore metamodels

  1. Kermeta plugin (remote site for a direct eclipse installation : http://www.kermeta.org/update ), version 0.1.0

  2. 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

Chapter 2. Create a meta-model for Kermeta programs

In this tutorial, we have chosen to show you how EMF and loading works with the classical example of finite state machines.

2.1.  Step by step

  1. Create a new simple project, call it, for example, MyFirstEMFSamples .

  2. Select in the toolbar menu (on top of Eclipse window) File > New > Other > Example EMF Creation Wizards folder > Ecore Model

    Selection of the model object (root element)

    Figure 2.1. Selection of the model object (root element)

  3. give a file name to your metamodel (e.g fsm.ecore), then click on Next button

  4. choose EPackage as the Model Object (the root of your metamodel), and click on the Finish button

    Selection of the model object (root element)

    Figure 2.2. Selection of the model object (root element)

  5. 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)

  6. 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;

  7. New empty ecore model

    Figure 2.3. New empty ecore model

    How to show properties view

    Figure 2.4. How to show properties view

  1. through this tab, you need to set 2 properties to your EPackage (which is displayed as null for the moment)

    1. its Name : fsm, for example;

    2. 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

  1. 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 :

New child on EPackage root node

Figure 2.5. New child on EPackage root node

    1. 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)

    2. a Transition (idem as Fsm class)

    3. a State

  1. 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.

  2. 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)

    Setting the properties of an EReference

    Figure 2.6. Setting the properties of an EReference

  3. 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

  4. don't forget to save your model

[Note]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.

2.2.  Resulting metamodel

At this stage of the tutorial, you should have the following metamodel:

a simple fsm metamodel

Figure 2.7. a simple fsm metamodel

2.3. EMF Metamodel creation tips

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:

  1. 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.

2.5.  Alternative ways to create a metamodel

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:

  1. Omondo / Eclipse UML has a nice graphical editor for ecore models.You can even generate the EMF editor directly from this tool.

  2. Kermeta: You can write your metamodel with kermeta and then translate it into ecore using the kermeta2ecore function.

Generate ecore metamodel from kermeta

Figure 2.8. Generate ecore metamodel from kermeta

[Tip]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.

Chapter 3. Create an EMF model from your metamodel

3.1. With the dynamic instance creation tool

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).

Create dynamic instance from an ecore file

Figure 3.1. Create dynamic instance from an ecore file

3.2. Using a reflexive editor

[Tip]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 )

3.2.1. Generate the editor

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:

  1. once your metamodel is created, you can create a model for model generation, called genmodel :

    1. File > New > Other > Eclipse Modeling Framework folder > EMF Models

    2. choose a name for your genmodel (fsm.genmodel is ok)

    3. select Load from an EMF core model button, and find your metamodel (fsm.ecore)

    4. select the unique package fsm

  1. 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.

  2. right-click on the root node of your fsm.genmodel, and choose the Generate all item.

3.2.2. Use the editor

  1. To be able to use the generated reflexive editor, you have to launch a new runtime workbench, through the tool bar menu:

    1. Run > Run As > Run-time Workbench (in eclipse 3.0.2)

    2. or Run > Run... > Eclipse application item in the right part > New button > Apply button > Run button at the bottom (eclipse 3.1)

  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

  2. 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)

  3. 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.

Chapter 4. Manipulate EMF models with Kermeta

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.

4.1. Preparing a Kermeta program

4.1.1. The persistence library

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) :

  1. instanciate an EMFRepository

  2. create a new EMF resource in this repository

  3. load this resource

  4. 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.

4.1.2. Your first Kermeta program using persistence

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
}

4.2. Load an EMF model with Kermeta

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

4.3. Modify and save an EMF model with Kermeta

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

4.4. Create a model in Kermeta, and save it as an EMF model

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):

Fsm_scratch_sample view

Figure 4.1. Fsm_scratch_sample view

    4.5. A template for a complete kermeta program

    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
    }
    

    Chapter 5. Metamodel with behavior and persistency

    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)

    1. kmt files(kermeta textual syntax)

    2. km files(kermeta model in xmi2.0)

    3. ecore files (ecore model in xmi2.0)

    4. 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]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]Note
    Kermeta2Ecore and Ecore2Kermeta transformations are available in the workbench (right click on an ecore or a kermeta file)