| <html> | |
| <head> | |
| <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252"> | |
| <title>From Front End To Code - MDSD in Practice</title> | |
| <link rel="stylesheet" href="../default_style.css"> | |
| </head> | |
| <body LINK="#0000ff" VLINK="#800080"> | |
| <div align="right"> <font face="Times New Roman, Times, serif" size="2">Copyright | |
| © 2006 Markus Voelter, Bernd Kolb, Sven Efftinge</font> | |
| <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> | |
| <div align="left"> | |
| <h1><img src="images/Idea.jpg" height=86 width=120 align=CENTER></h1> | |
| </div> | |
| <p> </p> | |
| <h1 ALIGN="CENTER">From Front End To Code - MDSD in Practice</h1> | |
| <blockquote> | |
| <b>Summary</b> | |
| <br> | |
| Model-driven software development (MDSD) is not just about generating code. Several | |
| additional challenges have to be mastered. These include: how to get usable | |
| graphical and textual editors for your domain specific language (DSL), how to validate your models against | |
| your metamodels, how to define model modifications and transformations and finally, | |
| how to write scalable, maintainable and extensible code generators. In this article | |
| we show how to tackle all these challenges, based on a collection of open source | |
| tools: Eclipse, Eclipse Modeling Framework (EMF), Graphical Modeling Framework (GMF) as well as openArchitectureWare. We believe that | |
| this tool chain provides a proven and stable stack for making MDSD a practical reality. | |
| <p><b> By <a href="http://www.voelter.de">Markus Voelter</a>, <a href="http://www.kolbware.de">Bernd Kolb</a>, <a href="http://www.efftinge.de">Sven Efftinge</a>, and <a | |
| href="http://www.haase-consulting.de">Arno Haase</a>, all Independent Consultants</b> <br> | |
| <font size="-1">June 15, 2006</font></p> | |
| </blockquote> | |
| <hr width="100%"> | |
| <h2>Introduction</h2> | |
| <p> | |
| For model-driven development it is essential that we provide an end-to-end tool chain. | |
| The following challenges arise: | |
| </p> | |
| <ul> | |
| <li>You'll need good editors for your models: This has traditionally been a problem | |
| that has been addressed by using Unified Modeling Language (UML) tools with profiles. With the advent of the Graphical Modeling Framework (GMF) and openArchitectureWare's (oAW) xText | |
| things are changing for the better. | |
| <li>Verifying the models as you build them: models must be verified for correctness interactively | |
| during modeling, as well as just before transformation/generation. | |
| <li>Transforming/modifying models: Models must be transformed into other models, or models | |
| must be "enriched" with additional information. | |
| <li>Generating code: code needs to be generated so we can execute the system described by the | |
| models somewhere. | |
| <li>Integrating generated and non-generated code: This is something that does require some | |
| thought – even if it sounds trivial. | |
| </ul> | |
| <p> | |
| Note that in this article we're not going to address issues such as why you would want to | |
| do model-driven software development (MDSD) at all, which advantages it has, how you'll have to organize your project, etc. | |
| If you're interested in these aspects (which we assume you already know for this article), | |
| we recommend reading [<a href="#SV06">SV06</a>]. We assume that you consider MDSD to be useful – and based on | |
| that, we'll show you how to do it effectively with today's tooling. | |
| </p> | |
| <h2>Roadmap</h2> | |
| <p> | |
| Our example is based on state machines. Everybody knows state machines, so this sounds | |
| like a reasonable example. We will start by defining a metamodel for state machines. | |
| This will be based on the UML metamodel. We use Eclipse Modeling Framework (EMF) to define it. | |
| We will then build a graphical editor for state machines using the well-known UML-based | |
| notation; for this task we'll use the Eclipse Graphical Modeling Framework (GMF) framework. We will then add additional | |
| constraints (e.g. "states must have unique names"). To make things more convenient, we'll | |
| use the oAW Checks language and integrate it with GMF. Next up will be a code generator | |
| that creates an implementation of state machines in Java. We use oAW's xPand language. | |
| We'll then create a set of recipes that help developers with the implementation of the | |
| actions associated with states – this illustrates the problem of integrating generated and manually | |
| written code. We will then cover model-to-model transformations and model modifications using | |
| oAW's xTend language. Finally, we will build a textual editor for rendering the state machines | |
| textually using oAW's xText framework. | |
| </p> | |
| <p> | |
| Note that all the code is available from | |
| <a href="http://www.eclipse.org/gmt/oaw/doc/s10_gmfAndOAW_src.zip">http://www.eclipse.org/gmt/oaw/doc/s10_gmfAndOAW_src.zip</a> | |
| </p> | |
| <h2>The Metamodel</h2> | |
| <p> | |
| The metamodel for state machines is probably well-known. A state machine consists of a | |
| number of states. States can be start states, stop states and "normal" states. A transition | |
| connects two states. States know their outgoing and incoming transitions. We also support | |
| composite states that themselves contain sub state machines. A state machine is itself a | |
| composite state. A state has actions. Actions can either be entry or exit actions. Here's | |
| the UML diagram for that metamodel, rendered with the GMF Ecore Modeler. | |
| </p> | |
| <p align="center"><img src="metamodel.gif"></p> | |
| <h3>Defining the metamodel</h3> | |
| You can either draw the metamodel in the editor as shown above, | |
| or you can also use the EMF tree editor as shown below. The next illustration | |
| shows the editor, with our metamodel opened. | |
| <p align="center"><img src="emfmm.gif"></p> | |
| <p> | |
| In the properties view, as shown in the next screenshot, you can adjust the properties | |
| of the metamodel elements. | |
| </p> | |
| <p align="center"><img src="emfprops.gif"></p> | |
| <p> | |
| You can find the metamodel in the oaw4.demo.gmf.statemachine2 project. | |
| </p> | |
| <h3>Generating the genmodel and the other necessary artifacts</h3> | |
| <p> | |
| To do useful work with this metamodel, we have to generate a number of artifacts | |
| (note that you could in theory work with dynamic EMF models, but for our case (GMF, | |
| Recipes, etc.) this will not work). First of all, you need to generate the genmodel. | |
| This is basically a decorator model (or a marker model) around our metamodel that | |
| "decorates" a number of extra properties on top of it. The yellow area | |
| in the following screenshot shows the genmodel file. If you're familiar with EMF | |
| you'll know how to generate it; if you're not familiar with EMF it's not important here. | |
| </p> | |
| <p align="center"><img src="generateEMFStuff.gif"></p> | |
| <p> | |
| Once you have generated the genmodel, open it, select the root element, and execute Generate | |
| All from the context menu. This is what will be generated: | |
| </p> | |
| <ul> | |
| <li>The implementation classes for the metamodel are generated. Take a look at the | |
| src folder of your metamodel project to see the effect. Each metamodel element now | |
| has a corresponding interface and implementation. | |
| <li>The .edit project (red in the previous screenshot) contains a number of utilities | |
| for building editors | |
| <li>The .editor project (also red in the previous screenshot) contains a tree-based | |
| editor, specific to that metamodel. After running this plug-in in a runtime Eclipse workbench, | |
| for example, you can define instances of your metamodel (i.e. actual state machines) | |
| with a tree view. We'll not do this now, since we'll use the graphical editor for that. | |
| <li>Finally, the .test project contains a number of tests for your metamodel. It is not | |
| relevant here. | |
| </ul> | |
| <p> | |
| As of now, there's no reason to look into any of these models or projects in more detail. | |
| You just have to make sure they're there. | |
| </p> | |
| <h2>Building the Graphical Editor</h2> | |
| <p> | |
| Building a graphical editor for your own DSL is probably the most complex and intricate | |
| of the steps of this tutorial. This is for two reasons. The first reason is that this | |
| tutorial has been written before GMF was finalized. So there are still a couple of | |
| glitches in the software (to get an updated tutorial, see [<a href="#GmfTut">GmfTut</a>]). The second reason | |
| is that building an editor is simply non-trivial! Before GMF arrived, you had to do it | |
| manually with the Graphical Editing Framework (GEF) which was a very daunting task (unless you'd write your own generator, | |
| as in [<a href="#RV05">RV05</a>]). Before even GEF, building a custom editor was not a viable alternative for | |
| most projects at all. So, GMF really is a huge step forward. And the remaining complexity | |
| is actually a joke, compared to what you'd have had to do pre-GMF. So let's get started. | |
| </p> | |
| <h3>Conceptual Overview / Project</h3> | |
| <p> | |
| For building a GMF editor (as shown in the next illustration) you start from your metamodel | |
| (the .ecore file) and the .genmodel defined above. We assume that these are already there. | |
| Also, the .edit and .editor projects generated from them are also assumed to be available. | |
| </p> | |
| <p> | |
| To get us a step further, a number of additional models have to be defined (we'll look | |
| into each of the later): | |
| </p> | |
| <ul> | |
| <li>A model defining the graphical notation including shapes, decorations and graphical | |
| nodes and connections. This is called the .gmfgraph model. | |
| <li>A model for the editor's palette and other tooling, called the .gmftool model. | |
| <li>A mapping model that binds these two models to the domain metamodel. The two models | |
| defined above are technically (but usually, not conceptually) independent of your domain | |
| metamodel. | |
| </ul> | |
| <p> | |
| Take a look at this illustration to understand how those models fit together. From all of these | |
| additional models, GMF creates the .gmfgen model – again a "low level" model that the code | |
| generator uses as an input, finally creating the .diagram project which contains your | |
| desired editor. | |
| </p> | |
| <p align="center"><img src="gmf.gif"/></p> | |
| <p> | |
| We use another project for the GMF models from which we'll create the editor: | |
| oaw4.demo.gmf.statemachine2.gmf. This project contains all the additional models just | |
| talked about. Here's a screenshot. | |
| </p> | |
| <p align="center"><img src="gmfproject.gif"/></p> | |
| <h3>The Tool Model</h3> | |
| <p> | |
| The .gmftool model defines – in our example – only a set of palette entries. The palette | |
| is the set of buttons (usually) on the right of an editor that allows you to add model | |
| elements to your model. So we need a creation tool for each of the metamodel elements that | |
| we want to be able to place onto the editor. | |
| </p> | |
| <p align="center"><img src="gmftool.gif"/></p> | |
| <p> | |
| We also assign icons to each of the of the creation tools. Note that we don't | |
| need a creation tool for the state machine itself, since the state machine will be | |
| represented by the editor itself (more specifically, it's Canvas). | |
| </p> | |
| <h3>The Graph Model</h3> | |
| <p> | |
| The graph model defines several (relatively separate) things. | |
| </p> | |
| <ul> | |
| <li>One is the set of figures defined in (one or more, potentially imported) FigureGalleries. | |
| Colors, line widths and static decorations are also defined here. | |
| <li>We also define graph nodes and connections. In the end, the editor consists of vertices | |
| connected by edges; those are defined here, too. | |
| <li>We also define compartments. Compartments are sections in nodes that can be collapsed | |
| and themselves contain graphs (or lists of elements). | |
| <li>Finally, we define diagram labels used to show text associated with graphical elements. | |
| </ul> | |
| <p align="center"><img src="gmfgraph.gif"/></p> | |
| <p> | |
| Looking at the screenshot above, you can see Nodes named after the metamodel elements we're going | |
| to map in a minute. In the properties (which you can't see here) we connect the Node elements | |
| to the respective figures; for example, the StateNode is associated with the StateRectangle. | |
| </p> | |
| <h3>The Mapping Model</h3> | |
| <p> | |
| This is the most complex model. Here we map the tool definition and the graph definition to | |
| the domain metamodel. For example (see the green part in the next screenshot) we map the | |
| normal States. We'll explain this mapping in some detail. To be able to actually map the | |
| various elements, you have to add these other Resources to the editor (see the yellow parts | |
| in the screenshot): | |
| </p> | |
| <ul> | |
| <li>For each metamodel element that we want to map directly onto the diagram surface (the state machine) we have | |
| to first define a Top Node Reference. | |
| <li>Below that, we add a normal Node Mapping. It contains information about the model element | |
| to map (State) and the property, in which the set of these elements is stored in the | |
| container (the container being the StateMachine here, the property that contains the | |
| states would be the EReference states). | |
| <li>Below the Node Mapping there's a Label Mapping. This one associates the label defined | |
| in the graph with the respective model element properties (here: the name of the state). | |
| <li>We also want to see the list of (entry and exit) actions in the state; so we have a | |
| Compartment Mapping below the Node Mapping. | |
| <li>We also have a Child Reference that identifies the set of children that should be shown. | |
| <li>The Child Reference is associated with the Compartment, to ensure that the child collection | |
| is actually shown in the respective compartment. | |
| </ul> | |
| <p> | |
| All of this has to be mapped with a number of properties; the editors for doing that are – as | |
| you can see – just the usual tree editors, which makes all of that stuff a bit cumbersome. | |
| There are additional, more specialized editors in the GMF pipeline that should make this process | |
| simpler (Some of the more specialized editors and wizards seem not to work that great at the time of this writing, or, | |
| more specifically, don't always provide the detailed level of control you'll need, so we | |
| use the tree editors). | |
| </p> | |
| <p align="center"><img src="gmfmap.gif"/></p> | |
| <p> | |
| The red part in the screenshot is a mapping of a link, links being the mappings of the | |
| edges of the graph. In the properties view, you can see some of the parameterization of | |
| the respective link: | |
| </p> | |
| <ul> | |
| <li>The Containment Feature is the EReference in the containing metaclass (here: StateMachine) | |
| that contains the reference objects (here: the Transitions). | |
| <li>Then we map the Element that should represent the Link; this is the Transition | |
| in our case. | |
| <li>Next we have to tell GMF which feature of the link metaclass (here: Transition) | |
| should take the reference to the source element (Source Feature) | |
| <li>We have to do the same thing with the target, this being stored in the Target Feature | |
| property. | |
| <li>We also have to define the graphical element (defined in the .gmfgraph model) that should | |
| represent the connection; here this is the TransitionConnection. | |
| <li>Finally we have to define which tool should be used to actually instantiate such a link. | |
| </ul> | |
| <p> | |
| That (and a number of details we didn't show here) finalizes the model definitions for GMF. | |
| </p> | |
| <h3>Generating the Editor</h3> | |
| <p> | |
| We now create the .gmfgen model from the set of models we just created (see the conceptual | |
| diagram above). From that, we can actually generate the diagram code – this will be contained | |
| in the .diagram project. | |
| </p> | |
| <p align="center"><img src="diagramproject.gif"/></p> | |
| <h3>Running the Editor</h3> | |
| <p> | |
| As usual, when generating editor plug-ins inside an Eclipse workspace, we have to use one of | |
| two possible ways to see the result: | |
| </p> | |
| <ul> | |
| <li>we either have to export the plug-in into the current Eclipse installation and restart it | |
| <li>or, we fork another Eclipse instance, a so-called Runtime Workbench (aka Eclipse Application) that | |
| contains the plug-ins that are in the workspace of the current Eclipse instance. | |
| </ul> | |
| <p> | |
| The following screenshot shows the running editor with an example state machine (a CD player) | |
| in the editor. This example state machine is located in a project called oaw4.demo.gmf.statemachine2.example. | |
| </p> | |
| <p align="center"><img src="runningEditor.gif"/></p> | |
| <h2>Constraints</h2> | |
| <p> | |
| Constraints are rules that models must conform to in order to be valid. These are in addition | |
| to the structures that the metamodel defines. Formally, constraints are part of the metamodel. | |
| A constraint is a boolean expression (a.k.a predicate) that must be true for a model to conform | |
| to a metamodel. | |
| </p> | |
| <p> | |
| Constraint Evaluation should be available in batch mode (when processing the model, see below) | |
| as well as interactively, during the modeling phase in the editor we just built ... and we don't | |
| want to implement constraints twice to have them available in both places! | |
| </p> | |
| <p> | |
| For defining constraints, functional languages are often used, OCL is the language of choice in the | |
| OMG/MOF/UML environment. | |
| As a consequence of the better tooling, we'll use openArchitectureWare's Check language. | |
| This language is very much like OCL. In fact, you'll probably not notice the differences in | |
| the examples that follow. | |
| </p> | |
| <h3>Constraint Definition</h3> | |
| <p> | |
| Since the constraints are conceptually part of the metamodel, we'll put the constraint | |
| definitions into the metamodel project, see the green area in the following screenshot. | |
| </p> | |
| <p align="center"><img src="constraintsInProject.gif"/></p> | |
| <p> | |
| As can be seen from the screenshot above, constraints are implemented in .chk files. | |
| openArchitectureWare comes with custom-made editors for the .chk files. The editors | |
| provide metamodel-aware code completion as well as error checking. The following | |
| screenshot shows a couple of constraints. | |
| </p> | |
| <p align="center"><img src="constraints.gif"/></p> | |
| <p> | |
| To see the power of the functional constraint language, you should take a look at the | |
| "States must have unique Names" constraint: | |
| </p> | |
| <ul> | |
| <li>typeSelect(TypeName) selects, from a collection of elements of type A, all elements | |
| that are actually of type B, B being a subtype of A. Note that the typeSelect(...) | |
| operation is statically typed to the TypeName given as the parameter. No need to cast! | |
| <li>forAll(...) returns true, if the expression in the second part returns true for all | |
| elements in the collection on which you call forAll(...) | |
| <li>exists(...) returns true, if the expression in the second part returns true for at | |
| least one of the elements in the collection on which you call exists(...) | |
| <li>There are more predicates, the most useful probably being select(x|expression-with-x) | |
| that selects all elements from a collection for which the expression is true. Note that | |
| collection.typeSelect(T) is actually an abbreviation of (Collection[T])collection.select(x|T.isInstance(x)) | |
| </ul> | |
| <p> | |
| To show off the editors, here's a screenshot of the editor in action :-) | |
| </p> | |
| <p align="center"><img src="constraintEditorError.gif"/></p> | |
| <h3>Integration into the GMF Editor</h3> | |
| <p> | |
| By default, the GMF-generated editor obviously doesn't know about oAW. To make the GMF | |
| generated editors evaluate our constraints, we needed to tweak things a little bit; most | |
| of this is in oaw4.demo.gmf.statemachine2.etc project. | |
| </p> | |
| <p> | |
| First of all, we wrote our own ConstraintEvaluators (a GMF/EMFT concept) and plugged in | |
| the oAW CheckFacade (the facade for oAW's constraint check system). We then used AspectJ to weave | |
| in the necessary notification adapters into the generated EMF Factory class (we really | |
| didn't want to modify the generated EMF classes!). We wrote a watchdog that does the batch | |
| evaluations whenever the model has changed (with a delay of two seconds). This relieves you from | |
| having to press the Validate button over and over again. Note that all of this stuff is actually | |
| part of the oAW/GMF integration package (released with oAW 4.1) so you don't have to | |
| care about the details. | |
| </p> | |
| <p> | |
| So what remains to be done for you as an editor developer is the following steps. | |
| First of all, you have to write a constraint class that loads the constraint file we wrote above. | |
| </p> | |
| <p align="center"><img src="BatchConstraint.gif"/></p> | |
| <p> | |
| You then have to plug these constraints into the EMF Validation Framework's constraintProvider | |
| extension point, as shown in the next screenshot. | |
| </p> | |
| <p align="center"><img src="constraintProviderXML.gif"/></p> | |
| <p> | |
| Finally, you have to make two important adjustments in the .gmfgen model (yes, to the generated | |
| .gmfgen model!), as shown by the green areas in the following screenshot. | |
| </p> | |
| <p align="center"><img src="gmfgenadjust.gif"/></p> | |
| <h3>Running the Editor again</h3> | |
| <p> | |
| Once you did all this you should be able to rerun the editor; you should get error messages | |
| right after (actually, 2 seconds after) you did something illegal, as per the constraints. | |
| </p> | |
| <p align="center"><img src="editoError.gif"/></p> | |
| <h2>Code Generation</h2> | |
| <p> | |
| Code Generation is used to generate executable code from models – usually the final result | |
| we want to get to. Code Generation is based on the metamodel and uses templates to | |
| attach to-be-generated source code. In openArchitectureWare, we use a template language | |
| called xPand. It provides a number of advanced features such as polymorphism, AO support | |
| and a powerful integrated expression language. We will show most of these features here. | |
| </p> | |
| <h3>Template/Metamodel interaction</h3> | |
| <p> | |
| Templates can access metamodel properties seamlessly, as shown in the next illustration. | |
| </p> | |
| <p align="center"><img src="propertyAccess.gif"/></p> | |
| <p> | |
| The code on the left is a template. Blue stuff is code that will be written to the to-be-generated | |
| file. The capitalized, purple code are template control structures such as FOREACH, IF or | |
| DEFINE (which I'll explain later). Finally, the black code is code that accesses the metamodel, as | |
| well as expressions involving metamodel properties. The expression states.typeSelect(State) can be | |
| explained as follows: | |
| </p> | |
| <ul> | |
| <li>We are in the context of a StateMachine. This is because the DEFINITION in which we're in is | |
| defined for the metaclass StateMachine. Like methods in Java, templates (DEFINE..ENDDEFINE) are | |
| associated with a specific metaclass. When the template is executed, there's an implicit this-pointer, | |
| referencing an instance of the respective metaclass. | |
| <li>So, since we can omit this, states references the same-named property of the StateMachine metaclass | |
| and thus returns a collection of the States inside the state machine. | |
| <li>Since we only need the normal States (and not start states and stop states), we do a | |
| typeSelect(...) to filter out what we need. | |
| </ul> | |
| <p> | |
| To complete this one, the FOREACH statement iterates over the result of the expression, assigns the | |
| current iterated element to the temporary variable s, and then executes the body of the | |
| FOREACH...ENDFOREACH block – which is generating some public static final int attribute. | |
| </p> | |
| <h3>What to generate?</h3> | |
| <p> | |
| What kind of code will be generated? How do you implement a state machine? You should think | |
| about what you want to generate before you start writing a generator. There are many ways of | |
| implementing a state machine: GoF's State pattern, If/Switch-based, Decision Tables or | |
| Pointers/Indexed Arrays. | |
| </p> | |
| <p> | |
| We will use the switch-based alternative. It is neither the most efficient nor the most elegant | |
| alternative, but it's simple. For more discussion of this topic, see Practical State | |
| Charts in C/C++ by Miro Samek [<a href="#MS02">MS02</a>]. So here's the outline of the code we want to generate: | |
| </p> | |
| <ul> | |
| <li>Generate an enumeration for the states | |
| <li>Generate an enumeration for the events | |
| <li>Have a variable that remembers the state in which the state machine is currently in. | |
| <li>Implement a function trigger(event) which | |
| <ul> | |
| <li>First switches over all states to find out the current state | |
| <li>Check whether there's a transition for the event passed into the function | |
| <li>If so, | |
| <ul> | |
| <li>execute exit action of current state, | |
| <li>Set current state to target of transition | |
| <li>Execute entry action of this new current state | |
| <li>Return | |
| </ul> | |
| </ul> | |
| <li>And also handle nested states :-) | |
| </ul> | |
| <h3>Organization of the Generator Project</h3> | |
| <p> | |
| The generator is located in the oaw4.demo.gmf.statemachine2.generator project. There are a number of | |
| code generation templates (green area in the following screenshot). Extensions are also defined | |
| (purple area). There are also workflow files (.oaw) that control the workflow of a generator | |
| run (orange area). Different workflow files contain different "parts" of the overall generator | |
| run and call each other. Workflow files are in some small way like ant files. | |
| </p> | |
| <p align="center"><img src="generatorProject.gif"/></p> | |
| <h3>Example Template</h3> | |
| <p> | |
| Here's an example template with a couple of annotations that explain what happens. | |
| Note that the template language uses a very "clean" syntax, using French quotation | |
| marks (for which the editor provides keyboard shortcuts :-)). | |
| </p> | |
| <p align="center"><img src="templateExample.gif"/></p> | |
| <h3>Extensions</h3> | |
| <p> | |
| Often, in the templates, you'll need additional properties on your metaclasses that | |
| are not defined in the metamodel itself. Examples are things such as a state machine's | |
| file name, the name of a state, in all-uppercase, to use as a constant, and other similar things. | |
| To keep the metamodel clean, these properties should not be defined in the metamodel itself | |
| (those properties aren't part of the problem space, rather, they are "helpers" useful for code | |
| generation). This argument becomes especially obvious if you consider the situation where | |
| you'd generate code for various target languages (say, Java, C++ and XML) from the same model. | |
| In that case you'd pollute your metamodel with all kinds of helpers. | |
| </p> | |
| <p> | |
| To avoid this, you can define extensions. Extensions can be called using member-style syntax: | |
| myAction.methodName(). Extensions can be used in xPand templates, They are imported into template | |
| files using the EXTENSION keyword. Check files, as well as other Extension files can also import | |
| extensions. Here's an example. | |
| </p> | |
| <p align="center"><img src="extFile.gif"/></p> | |
| <p> | |
| Extensions are written in oAW's expression language (the same language you used in the | |
| constraint checks). If, for some reason, the expressive power of the expression language is | |
| not enough, you can also escape to Java code. | |
| </p> | |
| <h3>Workflow Definition</h3> | |
| <p> | |
| A workflow definition is necessary to define the sequence of steps the generator executes | |
| in order to do something useful. In this first example, we need to execute the following steps: | |
| read the model, verify it (i.e. verify the same constraints we verified in the interactive editor) | |
| and generate code. | |
| </p> | |
| <p> | |
| Below is a screenshot of this simple workflow file. Workflow files are XML files that contain a | |
| number of workflow component declarations. Each workflow component declaration specifies the | |
| component class (such as oaw.emf.XmiReader) and a number of configuration properties. | |
| Note that you can use ${propName} notation as variables, just as in ant. | |
| </p> | |
| <p align="center"><img src="workflowexample.gif"/></p> | |
| <p> | |
| Just to recount: the CheckComponent in step two executes exactly the same constraints checks | |
| (the same .chk file) as the editor! There is something to be said about the expression | |
| model.eAllContents.union( {model} ). Basically what it does is that is returns a collection of all | |
| children of the element in the model slot, unioned with the element in the model slot itself. | |
| eAllContents is an Ecore primitive that returns all the children of an element, recursively, | |
| but not the element itself. Since we want all elements of the model, we have to union the children | |
| set with the set that contains only the model element itself. {...} is the literal set constructor in | |
| the oAW expression language. | |
| </p> | |
| <p> | |
| Also note that the generator component has the property skipOnErrors set to true. This | |
| means that this component is not executed if there are already errors in the workflow context, | |
| for example as a consequence of constraint checking in a previous step of the generator run. | |
| </p> | |
| <p> | |
| There's a bit more to be said about project organization. The variable ${modelFile} points to | |
| the actual file we want to generate. Now, the name of this file is something we cannot define | |
| as part of the generator project, since it's specific to the application. Remember that a generator | |
| is typically used in many applications! So, the workflow file we just defined is almost like | |
| procedure we'd like to call from somewhere else – from the application project, and that's also | |
| the way how we supply the value for the modelFile variable. | |
| </p> | |
| <p> | |
| So, inside the oaw4.demo.gmf.statemachine2.example project (that's the one where we'd "drawn" the | |
| CD player state machine) there's another workflow file, that looks like so: | |
| </p> | |
| <p align="center"><img src="exampleWorkflow.gif"/></p> | |
| <p> | |
| As you can see, it defines a value for modelFile and then calls the original workflow file using | |
| the cartridge file="..." construct. | |
| </p> | |
| <p> | |
| If you run that one, you'll see the code for the example state machine being generated into the | |
| src-gen folder in your example project. | |
| </p> | |
| <h3>AO templates</h3> | |
| <p> | |
| Consider somebody gave the generator we developed above to you, or you'd downloaded a "state machine | |
| cartridge" from somewhere. Now you notice that you want to adapt the code generator somehow, for | |
| example, you want to add log output, or you want the state machine to throw an exception if an event | |
| arrives which the state machine cannot handle in the current state (as opposed to just ignoring it, | |
| as it happens in the current implementation). | |
| </p> | |
| <p> | |
| How can you do that? How can you adapt the code generation process to your needs without hacking | |
| the existing templates? Well, aspect orientation provides a solution here, and openArchitectureWare | |
| supports aspect-oriented templates. | |
| </p> | |
| <p> | |
| Here's (almost all) of the code that's necessary to achieve that. | |
| </p> | |
| <p align="center"><img src="aspectExample.gif"/></p> | |
| <p> | |
| AROUND templates advice existing templates; you can use all kinds of wildcards to define the | |
| pointcut (i.e. the template to be advised). The joint point model is limited to template executions, | |
| so if you want to be able to advice a certain location in the template, you need to make sure | |
| that there's a DEFINE..ENDDEFINE block around it. In the worst case, you as the writer of the | |
| original templates have to add dummy templates (such as in the handleIllegalTransition case). | |
| This is the very same situation as in OO programming; in order to overwrite a piece of code | |
| in a subclass, this piece of code has to be modularized into a method (you can't override | |
| line 3 to 11 of a given method!). In AO this is fundamentally the same, however, the granularity of | |
| what you can advice depends on the joint point model. Most AO systems use method-level join points | |
| only (the equivalent being the template in our case); only AspectJ has some finer grained join points. | |
| </p> | |
| <p> | |
| To actually execute the templates, you have to tell the generator component that they are | |
| available. Now, the problem is, that the workflow file might also have been written by | |
| "the other guy" and you can't or don't want to change it. So what you need to do is to | |
| advise an existing component declaration and add the necessary properties. Fortunately, | |
| you can do this, too, the workflow engine also supports advices. Without going into all | |
| the detail (which you can find in the docs to openArchitectureWare), you can add the following | |
| code to the example workflow file (assuming, here, that the logging stuff we wrote above is | |
| specific to the example project): | |
| </p> | |
| <p align="center"><img src="aoworkflow.gif"/></p> | |
| <p> | |
| In the second component declaration, you use a GeneratorAdvice component and identify the | |
| target of the advice (the pointcut, so to speak) with the adviceTarget property. It identifies | |
| the original component by its name (if you go back to workflow file we showed, you'll | |
| see that the generator component had the ID "generator"). The semantics of the advice component is, | |
| that the properties added to the advice component will be "transferred" to the adviceTarget. | |
| So, in this case, this adds the <advices value="templates::Logging"> property to the original | |
| generator component, which, in turn, tells it about the template aspects. That's all you need to do. | |
| </p> | |
| <p> | |
| A final word on AO: Consider how useful this feature will be if you're building families of code generators, | |
| for example in embedded systems, where you'll often need to generate code for a number of (related) target | |
| platforms. Most of the code will be the same for all of those platforms; however, parts will be specific to | |
| the processor or OS abstraction layer, or whatever. You can then put all the common code into a set of | |
| templates and have the specifics organized into a set of AO templates, everything nicely modularized and | |
| organized! | |
| </p> | |
| <h2>Recipes – Integrating generated and non-generated code</h2> | |
| <p> | |
| In most scenarios, it is not useful, from a pragmatic point of view, to generate 100% of the | |
| application code. For example, in our state machine example, we don't generate the implementation | |
| of the actions (the code that is executed upon entry or exit of a state). This has to be written | |
| manually, and integrated with the code that has been generated. | |
| </p> | |
| <p> | |
| Since we don't like to use protected regions for various reasons (yes, openArchitectureWare supports them :-)), | |
| we need some other means. The next illustration shows a couple of alternatives such as inheritance, | |
| factories, template methods, etc. | |
| </p> | |
| <p align="center"><img src="codeInt.gif"/></p> | |
| <p> | |
| The problem that arises here is as follows: application development is not yet finished once | |
| the generator has terminated! Developers have to add the manual code in the right way. However, the | |
| generator cannot help developer "do the right thing" here, since it has already terminated! What you'd | |
| want is somebody telling the developers something like "hey, you have to add this action implementation | |
| to make the system complete". And of course, once you've added that code, that somebody should shut up | |
| and not bother you with the reminder :-) | |
| </p> | |
| <h3>Using Recipes</h3> | |
| <p> | |
| Well, that's exactly what you can do with the Recipe framework. It provides a task-based | |
| approach to "completing" the generated code with manual parts. This works the following way: | |
| </p> | |
| <ul> | |
| <li>As part of the generator run, you instantiate checks; these are written to a file | |
| <li>After the generator finishes, the IDE (here: Eclipse) loads these checks and verifies them | |
| against the complete code base (i.e. Generated + manual) | |
| <li>If things don't conform to the rules, messages are output helping the developer to fix things. | |
| </ul> | |
| <p> | |
| For example, in the state machine case, actions must be implemented in subclasses of the | |
| generated state machine implementation. Let's look at the effects: | |
| </p> | |
| <p align="center"><img src="recipeScreenshot.gif"/></p> | |
| <p> | |
| The code generator created a class AbstractCdPlayer (since the state machine was named | |
| CdPlayer in the model). We've already written a class CdPlayer (which is the required name | |
| for the implementation class) but we did not yet extend the base class. So the recipe check | |
| that verifies the existence of the CdPlayer class is green; the check that verifies that it has to extend the | |
| AbstractCdPlayer base class is still red. So you know what you need to do. Once you add "extends | |
| AbstractCdPlayer" to your class definition, and save it, the red mark will get green. | |
| </p> | |
| <p> | |
| Of course, then we'll get a number of compiler errors, because I have to implement the | |
| action methods. We decided not to provide a separate recipe check for each of them, although | |
| we could have done that. | |
| </p> | |
| <p align="center"><img src="comerr.gif"/></p> | |
| <h3>Implementing Recipes</h3> | |
| <p> | |
| Implementing Recipes is a two stage process. The first stage is to implement the elementary | |
| checks (such as class has to exist, or that a class has to extend a certain superclass). | |
| oAW comes with a number of predefined recipe checks for Java, you can also define your own | |
| checks, e.g. to verify C++ code. | |
| </p> | |
| <p align="center"><img src="recipeImplementation.gif"/></p> | |
| <p> | |
| The next step is to instantiate the checks as part of your workflow and write them to | |
| the external file which Eclipse can then load to validate the checks against the code base. | |
| To do this, we write a workflow component that does the work. Here's the code. | |
| </p> | |
| <p align="center"><img src="recipeWorkflow.gif"/></p> | |
| <h2>Model Modifications</h2> | |
| <p> | |
| Model modifications are a form of model transformation, where the source model is also the | |
| target model, i.e. the original model is modified. There's also model transformations, | |
| where one or more output models are created from one or more input models, leaving the inputs | |
| unchanged. Both of these tasks can be accomplished with oAW's xTend language, as we'll see. | |
| Alternatively, you can use any other EMF-based transformation engine, such as MTF or ATL. | |
| </p> | |
| <p> | |
| So what kind of modification would make sense? We decided to add an emergency shutdown to | |
| our state machine. So, we'll have to add an additional state (emergency stop) and a transition | |
| from each (normal) state to this emergency stop state. As usual, we have to do two things: | |
| write the transformation and plug it into the workflow. Here's the code for the transformation: | |
| </p> | |
| <p align="center"><img src="emergencyStop.gif"/></p> | |
| <p> | |
| There's a very interesting detail hidden in there: If you look closely, you'll find that | |
| createShutDown() is called several times; once from the modify(...) function, and then | |
| again from each of the createTransition(...) invocations. So, will we end up with several | |
| new States? The answer is no. The really cool thing about create extensions is that, for | |
| each set of parameters, it is evaluated only once. Subsequent invocations with the same | |
| set of parameters will return the identical object, the function is not reevaluated! | |
| So, since createShutDown() has no parameters, and thus, each invocation automatically | |
| is with the same set of parameters (the empty set) the createShutDown() function is executed | |
| only once. So each of the several invocations returns the same object. This is exactly what | |
| we want! | |
| </p> | |
| <p> | |
| The createTransition(...) function takes one parameter, the state for which is should create | |
| the transition to the emergency stop state. Note how the properties (event, name, from state and to state) | |
| are set. This extension is called and evaluated once for every state – again, exactly as we need it. | |
| </p> | |
| <p> | |
| Now, to make this transformation execute, we have to add something to the workflow file: | |
| </p> | |
| <p align="center"><img src="workflowForModification.gif"/></p> | |
| <p> | |
| The XtendComponent is told the metamodel as well as – and this is important – the initial expression | |
| to evaluate. trafo::AddEmergencyShutdown.modify(model) will invoke the modify operation in the | |
| AddEmergencyShutdown.ext file (By the time you read this, the delimiter between the file and the | |
| function (which is currently a dot) will probably have been changed to ::, which is the otherwise | |
| standard namespace delimiter in oAW.), which is in the trafo package (remember that oAW loads all | |
| resources from the Java classpath). The term "model" is the name of the slot into which the reader | |
| (see the component above the XtendComponent) has put the model's root object. | |
| <p> | |
| Model modifications and transformations can be a bit tricky. As of now we don't have debug | |
| support available (although we're working on it). Consequently, it is essential to test such | |
| a transformation. How to you do this? We won't show the code, just outline the process:</p> | |
| <ul> | |
| <li>You define an example model (such as the CD player) | |
| <li>You run the generator | |
| <li>In the workflow file of the example, after running the generator workflow, you add a | |
| CheckComponent that verifies an additional set of constraints | |
| <li>these constraints are specific to the example. They could verify things such as: | |
| there has to be exactly one state called EmergencyShutDown, from all normal states, | |
| there needs to be a transition that leads to that singleton EmergencyShutDown state, and so on. | |
| <li>By structuring your workflow files suitably, you can also run the specific constraints | |
| not after the generator has run, but rather, after the transformation. | |
| <li>You can also set up a specific workflow file that only reads the example model, runs | |
| the transformation, and then checks the specific constraints. | |
| </ul> | |
| <h2>Model Transformation</h2> | |
| <p> | |
| There's something we hadn't told you yet, and you probably didn't notice it either. And that is | |
| that the code generation templates aren't based on the same metamodel as the GMF editor. | |
| We could have based them on that same metamodel, and often that's a good choice, but to | |
| demonstrate model transformation, we added an "intermediate" model. | |
| </p> | |
| <p> | |
| So this intermediate metamodel is actually considerably simpler but contains all | |
| the necessary information to generate the code. Here's a screenshot of the simplified metamodel. | |
| </p> | |
| <p align="center"><img src="simplemm.gif"/></p> | |
| <p> | |
| As you can see, the inheritance hierarchies are removed, actions are restructured to be | |
| owned by the state machine, the bidirectional associations between states and transitions | |
| are removed, we have no composite states anymore, etc. etc. | |
| </p> | |
| <p> | |
| Obviously, we need a transformation that transforms the model we created in the GMF | |
| editor to a model that is an instance of that new metamodel. Here's the transformation. | |
| </p> | |
| <p align="center"><img src="gmf2simple.gif"/></p> | |
| <p> | |
| There are a couple of things in that file that are worth mentioning. | |
| </p> | |
| <ul> | |
| <li>First of all, there are two metamodels in use here. The unqualified metaclasses are from | |
| the statemachine2 package, i.e. the metamodel used in the GMF editor. They are unqualified, | |
| because the package is imported at the beginning of the file. If we want to work with a | |
| metaclass of the simple state machine metamodel (the metamodel just shown), we have to explicitly | |
| qualify it with simpleSM. | |
| <li>You can see a number of private functions. They can only be called from within the | |
| same extension file. | |
| <li>You can see that there's a switch statement available. Note that you have to specify a | |
| default case, since the switch itself will evaluate to a value - it is actually an expression! | |
| <li>You can see the same function defined for the different types. This works in case the | |
| types are different (overriding) or in case they're subtypes, in which case a polymorphic | |
| invocation will be performed. | |
| <li>cached functions are only evaluated once per unique set of parameters, as explained above. | |
| create functions are implicitly cached. | |
| <li>Finally, you can define strongly typed Collections as in List[Action]. | |
| </ul> | |
| <p> | |
| So as you can see the language used for model-to-model transformations is quite | |
| powerful and ready for practical use. This is even more true if you consider to metamodel-aware | |
| editor and the upcoming debugger. | |
| </p> | |
| <h2>A Textual Editor</h2> | |
| <p> | |
| It is not always useful to describe models in a graphical fashion. More often than you' | |
| d thing what you really want is a textual DSL. To make working with a textual DSL nice | |
| and easy, you'll probably want a nice editor for that language, one that features | |
| syntax coloring, real-time constraint checking and maybe even code completion. | |
| In short, you want the same level of convenience that GMF provides for graphical editors | |
| for your textual ones. xText can do that for you. | |
| </p> | |
| <h3>How xText works in Principle</h3> | |
| <p> | |
| The xText Framework works as follows: | |
| </p> | |
| <ul> | |
| <li>You define the syntax of your textual notation in an EBNF-like form. | |
| <li>You run the xText generator. It creates | |
| <ul> | |
| <li>a representation of the AST (the metamodel) as an EMF instance | |
| <li>a parser component that instantiates a dynamic instance of that metamodel when it | |
| parses the textual model; this component can be used in oAW workflow files! | |
| <li>Finally, it creates an Eclipse editor plug-in that provides a nice | |
| editor for the respective syntax. | |
| </ul> | |
| </li> | |
| <li>You can implement additional constraints (in oAW's Checks language, as usual), that | |
| are validated in real-time during the editing process</li> | |
| </ul> | |
| <h3>Defining an Editor for simple State Machines</h3> | |
| <p> | |
| In the context of this example, we want to provide an editor for the simple state machine metamodel | |
| (the one to which the transformation above transforms). The process to get there is as follows: | |
| </p> | |
| <ul> | |
| <li>define a concrete syntax, generate editors and parsers to build models | |
| <li>since the AST derived from that syntax is not identical to the simple state | |
| machine metamodel, we'll create another (simpler) transformation. | |
| </ul> | |
| <p> | |
| So let's start with the definition of the syntax: | |
| </p> | |
| <p align="center"><img src="grammar.gif"/></p> | |
| <p> | |
| The Grammar language consists of two core abstractions: Rules and Tokens. Currently, the following | |
| token types available: | |
| </p> | |
| <ul> | |
| <li>keyword or symbol (e.g. "state", "{") | |
| <li>ID (an identifier) | |
| <li>STRING (a string) | |
| </ul> | |
| <p> | |
| The main concept is Rules. Let's look at an example, the State rule from the above screenshot | |
| (the third paragraph). Each rule has a name (State). This is by convention the name of the | |
| corresponding AST type, so the generator will create a metaclass State. In our example, the concrete | |
| syntax for a state starts with the keyword state followed by an identifier (i.e. ID) which is | |
| assigned to the property "name" of the generated metaclass. Then an opening curly brace | |
| (i.e. "{") is expected. Next up one or more Actions (described in its own rule) are assigned | |
| to the reference entryActions. The '+=' operator specifies that entryActions is a list, and the | |
| Action should be added to it. Then one or more Transitions are added to the transitions reference, | |
| before the following actions are added to the exitActions reference. The description of a state is | |
| terminated using the closing curly bracket ("}"). | |
| </p> | |
| <p> | |
| As a consequence of this definition, the derivable (and thus, generated) metaclass State (also referred | |
| to in this context as AST type) needs to look as follows: | |
| </p> | |
| <ul> | |
| <li>a property name of type String | |
| <li>a reference entryActions of type List of Action | |
| <li>a reference transitions of type List of Transition | |
| <li>a reference exitActions of type List of Action | |
| </ul> | |
| <p> | |
| In addition to the rules that define concrete syntax (as shown above), there are also abstract rules. | |
| As an example, look at the AbstractState rule in the screenshot above. | |
| </p> | |
| <p> | |
| An abstract rule (preceded by the Abstract keyword) will result in an abstract AST type (AbstractState). | |
| The body of the rule consists of a sequence of alternative rules (here: State vs. CompositeState). Since | |
| the AST types of the alternative rules (State and CompositeState) must be compatible with this rule's | |
| abstract AST type (AbstractState), the metamodel generated by xText automatically contains a corresponding | |
| type hierarchy. Also, xText normalizes the types (i.e. moves properties contained in all subtypes | |
| to the abstract super type). The derived metamodel of the state machine example shows how all | |
| the general features for State and CompositeState have been moved to there common super type AbstractState. | |
| </p> | |
| <p align="center"><img src="grammarAST.gif"/></p> | |
| <p> | |
| Note that the automatic generation of the AST metamodel is optional! You could design it manually, if you want to. | |
| </p> | |
| <p> | |
| Of course, one piece of the puzzle is still missing: the constraints that should be validated | |
| in the editor haven't been defined yet. So let's do this; again, we simply write a .chk file, possibly | |
| accompanied by a set of extensions defined in an .ext file. Here's the metamodel (left side) and | |
| the defined constraints (right side). | |
| </p> | |
| <p align="center"><img src="xtextconstraints.gif"/></p> | |
| <h3>Running the Editor</h3> | |
| <p> | |
| Let's look at the generated editor. As mentioned, it provides syntax highlighting and | |
| real-time constraint checking (constraints are evaluated once you save the file; this is the | |
| standard approach in Eclipse). | |
| </p> | |
| <p align="center"><img src="generatedXtextEditor.gif"/></p> | |
| <h3>Integrating the Parser into the Workflow</h3> | |
| <p> | |
| Just as we used the models created by GMF in the example generator, we also want to | |
| be able to use the textually described state machines in a generator workflow. Here's a | |
| workflow file that shows that one. Some explanations are in order: | |
| </p> | |
| <ul> | |
| <li>first we declare a bean, that gets its contents from a file generated as part of the | |
| xText editor generation that declares the metamodel to be used | |
| <li>Then we call the parser cartridge, also generated by the xText generator. This cartridge reads | |
| the model and stores the instance in the "model" slot. | |
| <li>Then, as in the GMF example, we run the constraints that were already used in | |
| the generated textual editor | |
| <li>Next up is the transformation of the instance of the textual syntax into | |
| the simple state machine metamodel. | |
| <li>Finally, we call the backend cartridge; this one does the actual code generation based | |
| on the simple state machine instance. This is the exact same backend cartridge that's also | |
| used from in the GMF example after it has been transformed to the simple state machine metamodel. | |
| </ul> | |
| <p align="center"><img src="xTextworkflow.gif"/></p> | |
| <h2>Conclusion</h2> | |
| <p> | |
| This wraps up our tour of Eclipse, EMF, GMF and openArchitectureWare. We have seen a complete | |
| tool chain, from front end to code. Note that all the building blocks are nicely modularized | |
| and reusable, and each comes with nice Eclipse editor support. Future enhancements of openArchitectureWare | |
| will be take place in all kinds of directions (see our development roadmap at [<a href="#OawRm">OawRm</a>]); a | |
| particularly interesting area we are working on is debugger support. For more information on | |
| openArchitectureWare go to [<a href="#Oaw">Oaw</a>]. | |
| </p> | |
| <p> | |
| We would really like to give us feedback. You can reach us through the URLs | |
| given at the top of the article. | |
| </p> | |
| <h2>References</h2> | |
| <ul> | |
| <li><a name="GmfTut">[GmfTut]</a> GMF Tutorial Wiki, <a href="http://wiki.eclipse.org/index.php/Graphical_Modeling_Framework">http://wiki.eclipse.org/index.php/Graphical_Modeling_Framework</a></li> | |
| <li><a name="MS02">[MS02]</a> Miro Samek, Practical Statecharts in C/C++, CMP Books, 2002</li> | |
| <li><a name="Oaw">[Oaw]</a> openArchitectureWare, <a href="http://www.openarchitectureware.org">http://www.openarchitectureware.org</a> and <a href="http://www.eclipse.org/gmt/oaw">http://www.eclipse.org/gmt/oaw</a></li> | |
| <li><a name="OawRm">[OawRm]</a> oAW Development Roadmap, <a href="http://www.eclipse.org/gmt/oaw/roadmap.php">http://www.eclipse.org/gmt/oaw/roadmap.php</a></li> | |
| <li><a name="RV05">[RV05]</a> Rudorfer, Voelter, Domain-specific IDEs in embedded automotive software, <a href="http://www.voelter.de/data/presentations/EclipseCon.pdf">http://www.voelter.de/data/presentations/EclipseCon.pdf</a></li> | |
| <li><a name="SV06">[SV06]</a> Stahl, Voelter, Model-Driven Software Development, Wiley, 2006, see <a href="http://www.mdsd-book.org">http://www.mdsd-book.org</a></li> | |
| </body> | |
| </html> |