Skip to main content
Jump to: navigation, search

Difference between revisions of "Graphical Modeling Framework/Tutorial/Part 2"

m (Validation)
m (Validation)
Line 204: Line 204:
To begin, open the mapping definition (mindmap.gmfmap) and right-click the Mapping node. Select 'New Child... Audit Container' and give it a name (e.g. Mindmap Audits). Assign it an id and description as well. To the container, add a new 'Audit Rule' named 'Cyclic relationship check'. We are going to target the Map class for the audit, so add a child 'Domain Element' to the Audit Rule and select 'EClass Map' as the Element. Add a new child 'Constraint' to the Audit Rule and enter the following for the Body, leaving the Language set to ocl.
To begin, open the mapping definition (mindmap.gmfmap) and right-click the Mapping node. Select 'New Child... Audit Container' and give it a name (e.g. Mindmap Audits). Assign it an id and description as well. To the container, add a new 'Audit Rule' named 'Cyclic relationship check'. We are going to target the Map class for the audit, so add a child 'Domain Element Target' to the Audit Rule and select 'EClass Map' as the Element. Add a new child 'Constraint' to the Audit Rule and enter the following for the Body, leaving the Language set to ocl.
<pre>self.relations->forAll(r1, r2 | = r2.source and r1.type = r2.type
    implies <> r1.source)
Line 211: Line 215:
<br style="clear:both;"/>
<br style="clear:both;"/>
<pre>self.relations->forAll(r1, r2 | = r2.source and r1.type = r2.type
    implies <> r1.source)
This will only detect cycles that exist between two directly linked Topic elements, but is sufficient for our purposes here. If someone more OCL-savvy can provide a statement to detect cycles between more than two Topics (if possible), it would be appreciated ;).
This will only detect cycles that exist between two directly linked Topic elements, but is sufficient for our purposes here. If someone more OCL-savvy can provide a statement to detect cycles between more than two Topics (if possible), it would be appreciated ;).

Revision as of 08:41, 12 April 2006

In this second part of the GMF Tutorial, some of the more advanced capabilities of the generation and runtime frameworks will be explored. Specifically, information on adding compartments, connections, feature initializers, diagram validation, and nested child nodes will be covered. A project containing the full solution set of projects for this segment is found here. Viewlets will be available after appropriate sections below to focus their content and keep them short.



Let's add a compartment to our Topic node to allow discussion threads to be added. In order to illustrate how to allow nodes within compartments, we will represent Thread items as yellow sticky notes and allow ThreadItem elements to appear as list items within them. So, we will have nodes with a compartment list nested within a parent node compartment. A preview of where we're going is seen to the right. And yes, it's a bit contrived, but it does give us an opportunity to combine a lot of features in one section.

Some of the steps in this section are a bit complex, so the viewlet should prove helpful in getting things right. Of course, in the future an improved user interface will be provided to hide some of the complexities found here, but for now consider it an opportunity to see how things really work ;)

Graphical Definition

Rounded figure.png

Open up your graphical definition again and let's first take care of giving our Topics a rounded rectangle. Right-click the Figure Gallery and add a new Rounded Rectangle, naming it RoundedTopicFigure. Adjust the Corner Width and Height property values to 20 (or whatever you'd like). To alter the default line color, right-click on the RoundedTopicFigure and add a new Child | Foreground Color RGB Color with R=220, G=220, B=250 (or whatever you'd like).

We'll reuse the old TopicFigure rectangle for our sticky note. Rename it StickyNoteFigure and give it a Background Color RGB Color child with values R=250, G=250, B=190 (a pale yellow, but feel free to change to suit your taste). Rename its child Label to StickyNoteNameFigure.

We'll need to create a child Label on our new Rounded Rectangle named TopicNameFigure, as was the case in the original Rectangle. With that, change the Diagram Label TopicNameLabel to use this new TopicNameFigure as its Figure. Then, just change the Figure property on your TopicNode to use this figure and not the Rectangle TopicFigure.

Create a new Node on the Canvas to use this figure and name it ThreadNode, along with a new Diagram Label named StickyNoteNameLabel on the Canvas that uses the StickyNoteNameFigure.

Compartment graph.png

As we'd like to have discussion threads within a compartment of our topic nodes, we'll need to add one to our Canvas by right-clicking and selecting New Child | Compartment. Give it the name ThreadCompartment and select RoundedTopicFigure for its Figure property.

We'd also like to give threads their own compartment to contain a list of thread items for the subject. Create another compartment for our ThreadNode named ThreadItemCompartment which will use StickyNoteFigure as its Figure. So, our topics will be rounded rectangles which will contain child rectangles within a compartment. These child rectangles will also have a compartment, but they will not contain rectangles, but rather, just a simple list of discussion threads. These will be represented with a Label.

Label graph.png

Add a new Rectangle and child Label to the Figure Gallery for our thread items named ThreadItemFigure and ThreadItemLabelFigure, respectively. Create a corresponding Node on the Canvas named ThreadItemNode and set its Figure to the ThreadItemFigure. Likewise, add a Diagram Label to the Canvas named ThreadItemLabel and assign the ThreadItemLabelFigure as its Figure property.

In summary, you should now have three nodes, one connection, two compartments, and three diagram labels as shown in the figure. These correspond to the Rectangles, child Labels, and our Polyline Connection in the Figure Gallery.

Note : In the future, graphical definitions will be done using a designer bootstrapped by GMF itself. The figures you have created here will be done visually, rather than by manipulating a model using the generated EMF editor.

Tooling Definition

Thread tool.png

We'll need a tool to add Thread nodes and ThreadItems, so open mindmap.gmftool and copy/paste the Topic tool and rename Thread. Repeat for a ThreadItem tool. Next, we'll need to complete our mappings, so reopen your mindmap.gmfmap file.

Mapping Definition

Compartment map.png

First, we'll need to add a new Compartment Mapping to our TopicNode Node Mapping and select ThreadCompartment for its Compartment property. Also, add a Child Reference to the Node Mapping. In the properties, select 'EReference comments' for its Containment Feature and Compartment Mapping <ThreadCompartment> for the Compartment.

Tip : There are 2 'EReference comments' listed in the dropdown list of our Containment Feature. The one we want is from the Topic class in the domain model, and it should be the bottom one on the list. Unless you use a later build of GMF, a way to ensure you've selected the correct feature is to open the mapping model in a text editor and verify the correct parent is in the path.

Right now, the node that represents our topic has a compartment with a reference to the domain element which will contain its contents. The contents of this compartment we have decided will be thread discussions, which are represented by yellow sticky notes. To represent this in our mapping, add a Node Mapping to our Child Reference. In the properties, select our Thread class for the domain Element, our ThreadNode for the Diagram Node, and our Thread creation tool from the palette.

The last thing we'll need for our child thread node is a mapping to its label. To our ThreadNode mapping, add a child Label Mapping. Select our ThreadNameLabel for the Diagram Label and the 'EAttribute subject' feature from our Thread class for the label's Feature property. Yes, this dialog is another place where it would help to know from which class these attributes come.

Run thread compartment.png

At this point, you can regenerate the generator model and diagram plugin to see how things look. As you can tell from the image here, discussion threads are now represented as list items in our topic compartment. Let's continue on and map our thread node compartment to display thread items.

Tip : In the generator model, you will find a property on the compartment that will allow you to show children as nodes and not a list, if you prefer. The property is 'List Layout' and should be set to 'false' in this case.

Thread Item compartment.png

We will basically repeat the steps above to add a Compartment Mapping for our ThreadItemCompartment. Also, add a Child Reference for our 'EReference items' feature on our Thread class and select ThreadItemCompartment for its Compartment.

To our Child Reference, add a child Node Mapping for our ThreadItem class with corresponding ThreadItemNode and ThreadItem tool. Finally, add a Label Mapping to the node for our ThreadItemLabel to display the 'EAttribute body' feature of our ThreadItem class.

At this point, you can regenerate the mindmap.gmfgen model and diagram plugin code. You should be able to run the diagram and produce a diagram similar to the one shown at the beginning of this section.

Link Constraints


Currently, the diagram will allow you to make a subtopic link from one Topic to itself, as seen here. Clearly, this does not make sense for our Mindmap, so we'd like to prevent this somehow. This section makes for a very short viewlet.

Link constraint.png

Let's return to our mapping definition, and to the 'Link Mapping' we created earlier. To add a constraint, we begin by right-clicking on the 'Link Mapping' and selecting 'New Child > Link Constraints'. To the Link Constraint, right-click and select 'New Child > Source End Constraint'. The 'Language' property defaults to 'ocl' and we'll need to add the following OCL statement to the 'Body' property: oppositeEnd.oclIsUndefined() or self <> oppositeEnd, as seen in the image below. Then, go through the usual regeneration of mindmap.gmfgen and diagram code and try it out. You will no longer be able to make a link from a Topic to itself.

Note: the expression above is different than in previous versions of this tutorial, and is expected to return to just 'self <> oppositeEnd' when a bug in EMFT OCL is fixed.

So, now to explain what is happening here. As you can tell from the context above, we've added a constraint to the creation of a link, based on its source end; that is, the Topic element from which a link is being created. In the OCL we've specified the only condition that will evaluate to true, and therefore allow the link to be created, is the condition where the source element is not equal to the 'oppositeEnd' of the link (the target). In this case, the context of 'self' is the source Topic, and 'oppositeEnd' is a custom variable added to the parser environment for link constraints.

Clearly, this is a very simple constraint, and one that could very well have been defined in the domain model itself and respected by the graphical editor automatically. We will look more closely at constraints in future versions of this tutorial as support for their use matures.

Another Connection

Dependency link def.png

Let's look now at the 'Relationship' element of our domain model. It specifies a number of possible relationships that may be indicated between Topic elements, in addition to the subtopic relationship we have supported thus far. We will add support for this type of Connection, as it will illustrate more completely the properties available for a Link Mapping within GMF. A viewlet of this section can be found here.

Graphical Definition

Returning to our graphical definition model (mindmap.gmfgraph), let's right-click on our gallery and add a 'New Child > Polyline Connection'. Name it 'DashedLineOpenArrow' and change 'Line Kind' to LINE_DASH. Then add a 'New Child > Polyline Decoration' element to the Figure Gallery and name it 'OpenArrow'. Add three Template Point children to the OpenArrow with X:Y values of -1:1, 0:0, and -1:-1. Finally, add the OpenArrow as a Target Decoration to the DashedLineOpenArrow polyline.

Now that you have the figure defined, create a corresponding Connection on our Canvas named 'RelationshipLink', selecting our 'DashedLineOpenArrow' as its 'Figure'.

Tooling Definition

We'll need a tool to create these links, so reopen your mindmap.gmftool model. We already have one link tool for subtopics, but it's in the same tool group as our node elements. Let's create a new Tool Group under our Palette for links named 'Links' and add to it new Relationship Creation Tool. Copy/paste the TopicSubtopics tool into this new group and name it simply 'Subtopic'. Delete the old TopicSubtopics tool. Finally, rename the 'mindmap' tool group to 'Nodes'.

Mapping Definition

Dependency link mapping.png

In the mapping definition, due to our changes in the tooling model, you'll need to update your tool selection for the Subtopic Link Mapping to our new Subtopic tool. Then, create a new 'Link Mapping' and fill in its properties to match what's displayed in the image.

Tip : Be aware of such limitations when working with multiple models, as until there is true refactoring support, you will need to be conscious of changes in definition models and how they will impact 'downstream' models, such as our mapping model. Drag and drop was available to move the existing TopicSubtopics tool to our new Links group, but would have resulted in a need for more cleanup in our mapping model.

In this mapping, we'll start with the 'Domain meta information > Element' property. It represents the element represented by this link in the domain, which is simply the 'EClass Relationship' element. Recall that in our previous link mapping, we left this and other properties blank. In that case, our target element for the link was represented by an element (Topic) added to a list of reference held in our source element (also a Topic). In this case, the link is represented in the domain by a class of its own, so more information is required in the link mapping. This class, the Relationship class of the domain model, is contained in a list of references in the Map element, which explains the 'Domain meta feature > Containment Feature' map to 'EReference relations'.

Continuing the mapping description, the 'Target Feature' in this case is mapped to the 'EReference target' domain model element, indicating that targets of the link are added to this list in the domain when the link is created. Similarly, the 'Source Feature' maps to the 'EReference source' domain model element. And of course, we have our straightforward tool mapping and 'Diagram Link' mapping to our RelationshipLink.

Dependency link.png

Now, we can regenerate our diagram code as before, launch our diagram workspace and test this new link. Here is an example of the results.

What we will now need to do is initialize the link to be of the proper type (dependency, includes, extends) when created. We will use separate tools for each, and could also opt to use distinct visualization. For now, we'll simply add a label to the link to indicate its type and maintain the dashed line with open arrow appearance for each.

Feature Initializers

When you create a new element on a diagram, there is typically a domain element created or modified as a result. In some cases, it's necessary to provide additional initialization information to ensure that objects are properly created. For example, the links we create between topics in our mindmap diagram come in three flavors: dependency, includes, and extends. The 'type' attribute of the Relationship class is used to hold the RelationshipType enum value for the new instance.

In our graphical definition, we will create a figure and corresponding link for each type, along with a creation tool for each in our tooling definition. We'll then use a feature sequence initilizer in our mapping definition to properly initialize our domain objects, depending on the type of link created on the diagram.

Another initialization we will perform is to set the 'label' attribute of the Relationship. As we've indicate above, this will serve to distinguish between the types as our visualization will remain the same for each. A viewlet of this section can be found here.

Graphical Definition

First, we need to add a Label to our graphical definition to use in displaying the relationship type. Add a new child Label to our Polyline Connection DashedLineOpenArrow and name it DashedLineLabelFigure. Right-click on the Canvas and add a new Diagram Label named 'RelationshipLabel' with a Figure assigned to our DashedLineLabelFigure.

Tooling Definition

Tool links.png

Return to our tooling model and rename the 'Relationship' tool to 'Dependency'. Copy/paste this tool in order to create additional 'Includes' and 'Extends' tools.

Mapping Definition

Similarly, in the mapping model, first verify the tool used by our current Relationship Link Mapping is set to the 'Dependency' tool. After we add the initializers, we will copy/paste this Link Mapping and change the properties to be used for includes and extends links. In the end, we will have a single link in our graphical definition being used by 3 tools with corresponding mappings to the same domain element.

Feature init.png

In the mapping model, below your dependency Link Mapping, create a 'Feature Seq Initializer' element. This will hold subsequent 'Feature Value Spec' elements as seen in the figure. OCL is the language currently supported, so be careful that the body expressions you enter are valid. In the case of initializing the enumeration field, you'll enter 'RelationshipType::DEPENDENCY' to set the 'EAttribute type' feature of our Relationship class. In the case of initilizing the 'EAttribute label' feature, you'll enter the string value 'depend' (within single quotes). Lastly, we'll need to provide a new Label Mapping to let the 'EAttribute label' feature of our Relationship domain element be represented by our RelationshipLabel.

Copy/paste your Dependency Link Mapping to create an Include and Extend link mapping, changing their properties as necessary (e.g. 'RelationshipType::INCLUDES' and 'RelationshipType::EXTENDS' with corresponding 'includes' and 'extends' body values).

Tip : Keep in mind that the order of the 'Feature Value Spec' elements will determine the order in which they are executed.

With these steps complete, we can regenerate our mindmap.gmfgen and code. When the diagram code is generated, below is what willl be generated within the Initializers inner class of MindmapElementTypes:

public static final ObjectInitializer Relationship_3003 = new ObjectInitializer(
	new FeatureInitializer[] {
			new FeatureInitializer(
					"RelationshipType::DEPENDENCY", //$NON-NLS-1$

			new FeatureInitializer(
					"'depends'", //$NON-NLS-1$


During link creation, the following code is executed in CreateIncomingRelationship3XXXCommand, found in the TopicItemSemanticEditPolicy class:

protected EObject doDefaultElementCreation() {
	Relationship newElement = (Relationship) super
	if (newElement != null) {
		newElement.setTarget((Topic) getTarget());
		newElement.setSource((Topic) getSource());
	return newElement;

This generated code within FeatureInitializer will ultimately be called on each value spec you've added, which as you can see constructs an OCL query for evaluation and uses the result to initialize the field you selected.

void init(EObject contextInstance) {
	if (this.query == null) {
		this.query = QueryFactory.eINSTANCE.createQuery(
				expressionBody, contextClass);
	Object value = query.evaluate(contextInstance);
	if (sFeature.getEType() instanceof EEnum
			&& value instanceof EEnumLiteral) {
		value = ((EEnumLiteral) value).getInstance();
	} else if (value != null && sFeature.isMany()) {
		value = new BasicEList((Collection) value);
	contextInstance.eSet(sFeature, value);

Runtime init.png

If you launch your runtime instance and test these new initializers, you will find that the type attribute is set according to the Relationship tool selected, and that the label attribute is preset to the names you defined above.


As we saw with the OCL constraint added in the first part of the tutorial, it is possible to restrict connections made between nodes by declaring constraints in our mapping definition. Sometimes, it is more appropriate to validate connections and other aspects of a diagram content using batch or even "live" validation using the Validation framework provided by the EMF Technology project. In this section, we will add such a validation feature to our mindmap in order to alert us of cyclic dependencies that have been created between Topics.

Audit rule.png

To begin, open the mapping definition (mindmap.gmfmap) and right-click the Mapping node. Select 'New Child... Audit Container' and give it a name (e.g. Mindmap Audits). Assign it an id and description as well. To the container, add a new 'Audit Rule' named 'Cyclic relationship check'. We are going to target the Map class for the audit, so add a child 'Domain Element Target' to the Audit Rule and select 'EClass Map' as the Element. Add a new child 'Constraint' to the Audit Rule and enter the following for the Body, leaving the Language set to ocl.

self.relations->forAll(r1, r2 | = r2.source and r1.type = r2.type 
     implies <> r1.source)

Tip : When authoring these constraint expressions in OCL, you may find it helpful to contribute an action to open the OCL Interpreter view on instances of your domain model. See the OCL Interpreter Example in the online documentation for more information.

This will only detect cycles that exist between two directly linked Topic elements, but is sufficient for our purposes here. If someone more OCL-savvy can provide a statement to detect cycles between more than two Topics (if possible), it would be appreciated ;).

Validation extensions.png

After reproducing the mindmap.gmfgen model, you will need to set the 'Validation Enabled' property of the Gen Diagram element to 'true' in order for the new audit to be run. Just below that property is one called 'Validation Provider Priority' that you should set to 'Medium' (something higher than 'Lowest'). Do this and regenerate your editor code. After doing so, you will notice some new extensions listed in your editor's plugin.xml file. Primarily, you should notice the constraintProviders and constraintBindings extension-points to which your editor contributes. Examine these and take a closer look at the EMF Validation framework if you wish.

An improvement here would be to write validations that identify the offensive element to allow for selection via the problems view. Currently, violations result in the canvas itself being selected, as the context is the Map and not a particular Topic or Relationship.

Audit violation.png

To test the new audit, launch your runtime workspace and create a dependency link between two Topic elements. Then, from the Diagram menu, select 'Validate' and observe an error in the Problems view, as shown here. To enable/disable the audit, you can find it now listed in the preferences dialog under 'Validation Constraints'.


In order to share content between diagrams, and indeed between domain model instances, GMF provides the capability to allow shortcuts to be added to diagrams. In order to enable this functionality, you'll need to locate the 'Shortcuts Provided For' and 'Contains Shortcuts To' properties of the Gen Diagram root of your generator model (e.g. mindmap.gmfgen). In order to allow the shortcutting of Mindmap elements, set both of these properties to 'mindmap' and regenerate your editor. A viewlet of this section can be found here.

Shortcut element.png

Test the shortcut capability by creating two new Mindmap diagrams and adding elements to each. On one, right-click and select 'Create Shortcut...' to bring up a selection dialog. Browse to the other diagram and select a Topic node to add as a shortcut.

There is understandably no viewlet for this section.


In this section of the tutorial, we saw how to add compartments (including nested nodes), links representing classes, feature initializers, constraints, validation, and shortcuts. The next section of the tutorial will dig deeper and focus on altering generated output and manual extension of the editor.

Back to the top