Skip to main content
Jump to: navigation, search

Graphical Modeling Framework/Tutorial/Part 2

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 feature initializers, diagram validation, nested child nodes, and manual extension of generated features will be covered.


Compartments and Connections

Comment.png

Let's return to our diagram definition and add a compartment to our TopicNode to allow for Comment elements to be added. First, add a new child for Comment elements to the Canvas by adding a 'New Child > Child' and name it CommentChild. For its Figure, select your new 'BasicRectangle'. Now we need to add a Compartment to hold the CommentChild elements. To do this, right-click on the Canvas element and select 'New Child > Compartment'. In the properties view, give it a name 'CommentCompartment'. Target your BasicRectangle figure by selecting it for the 'Figure' property.

Compartment.png

While we're here, let's go ahead and add a Connection element, as we'd like to indicate a subtopic relationship between Topic nodes on our diagram. In the Figure Gallery, add a new 'Polyline Connection' with a simple 'BasicLine' name and adjust the other properties as you see fit. Add the link we'll need between topics by right-clicking on the Canvas element and selecting 'New Child > Connection'. Give it the name 'TopicLink', selecting our new BasicLine from the gallery.

Link mapping.png

Now, reopen the mapping model so that we can associate this new link and compartment with our domain elements and assign them tooling. Begin by right-clicking on the Mapping element and selecting 'New Child > Link Mapping'. Fill in the Link Mapping's properties in accordance with the image below, and also add a Creation Tool child element:


In this case, the mapping is rather simple. The 'Diagram Link' maps to our only 'Connection' element, 'TopicLink'. The 'Domain meta information > Target Feature' is required and maps to the 'EReference subtopics' element, meaning that the target of the connection (another Topic element) will be added to this reference list within the source Topic. Finally, our Tool used for creating the links is mapped to the 'Creation Tool TopicSubtopics' element from our tooling definition.

Tip : A level of validation is available for mapping definitions and will take place prior to creation of the generator model. For example, remove the mapping for 'Target Feature' on a Link Mapping and attempt to create the mindmap.gmfgen model. When you do, you will receive an error message indicating that the property is required.

Compartment mapping.png

To explain the mappings, starting with the properties of the 'Compartment Mapping' element, we see that 'Visual representation > Compartment' maps to our only option, 'Compartment Mapping <CommentCompartment>'. The property 'Misc > Child Nodes' was filled in for us when we selected 'CommentCompartment' for the 'Misc > Compartment' property of the 'Child Node Mapping'.

Let's now look at the remainder of its mappings, as shown above. The domain model element 'EClass Comment' is selected for the 'Domain meta information > Element', with its 'EAttribute body' selected for the 'Edit Feature'. As with the Topic mappings described above, this is simply saying that elements of the Comment compartment are representations of Comment domain model instances in a diagram, with their 'body' attribute displaying as the element's editable field in the compartment. The 'Containment Feature' maps to the 'EReference comments' element, as new Comments added to the compartment will be added to this list held within a Topic. Finally, the 'Diagram Node' itself and its 'Tool' map as you would expect to the 'Child CommentChild' and 'Creation Tool Comment' elements, respectively.

Tip : Don't forget to assign a 'Tool' for your mapped diagram elements!


Complink.png


Now we're ready to regenerate the mindmap.gmfgen model and the code for our plug-in. Do this as before and test the new compartment and connection capabilities for the diagram.

Tip : Try this: if you'd like to create a diagram from an existing instance of a domain model, right-click the file and select 'Initialize xxx diagram file' where 'xxx' represents your domain_diagram editor extension. Note that an 'Arrange all' is likely your next step.

Constraints

Link2self.png

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

Tip : Before continuing on with this section, be sure you have copied the antlr.jar file into the 'lib' folder of the plug-in, as referenced on the download page for GMF. The OCL capabilities are temporarily dependent on ANTLR, which is not bundled with GMF. Also, note that the EMF Technology (EMFT) project now has downloads and more information on the OCL and model validation components here.


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

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.

Returning to our graphical definition model (mindmap.gmfgraph), let's right-click on our gallery and add a 'New Child > Polyline Connection'. Name it 'DependencyLine' and change 'Line Kind' to LINE_DASH. Then add a 'New Child > Target Decoration Polyline Decoration' element to the DependencyLine and name it 'ArrowDecoration'. Now, create a corresponding Connection within our Canvas named 'DependencyLink', selecting our 'DependencyLink' as its 'Figure'.

Dependency link mapping.png

In the mapping definition, create a new 'Link Mapping' and fill in its properties to match what's here:

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 'Label Display Feature' and 'Label Edit Feature' are both mapped to the 'EAttribute label' feature of the Relationship class. 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 Meta Feature' maps to the 'EReference source' domain model element. And of course, we have our straightforward tool mapping.


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

Dependency link.png

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 possible initialization is to set the 'label' attribute of the Relationship as well, if the appearance of the link is not enough to distinguish between the types.

Graph links.png

First, create a three distinct polyline connections with properties and decorations as you see fit. For each add a connection for each of the new Dependency, Includes, and Extends links as shown in the figure. For each connection, create a Creation Tool in your mindmap.gmftool model.

Tip : Don't forget that you can use copy/paste to duplicate elements in your models. This will come in handy as you create three links, connections, tools, and mappings.


Feature init.png


In the mapping model, for each of your Link Mappings, 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' while in the case of initilizing the label attribute, you'll enter the string value within single quotes. 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$
					MindmapPackage.eINSTANCE.getRelationship(),
					MindmapPackage.eINSTANCE.getRelationship_Type()),

			new FeatureInitializer(
					"'depends'", //$NON-NLS-1$
					MindmapPackage.eINSTANCE.getRelationship(),
					MindmapPackage.eINSTANCE
							.getRelationship_Label())

	});

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

protected EObject doDefaultElementCreation() {
	Relationship newElement = (Relationship) super
			.doDefaultElementCreation();
	if (newElement != null) {
		newElement.setTarget((Topic) getTarget());
		newElement.setSource((Topic) getSource());
		MindmapElementTypes.Initializers.Relationship_3004
				.init(newElement);
	}
	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.


Validation

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 '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 select 'EClass Map' and set the remaining properties in accordance with the figure. Add a new 'Constraint' to the Audit Rule and enter the following for the Body, leaving the Language set to ocl.

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.


self.relations->forAll(r1, r2 |  r1.target = r2.source and r1.type = r2.type 
     implies r2.target <> 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 ;).

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


Shortcuts

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.

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.


Nested Child Nodes

Manual Extension

Summary

Back to the top