Chapter 4. Developing a DSL Graphical Notation

In many cases, a domain-specific language (DSL) can be represented using graphical notation. Of course, not every DSL has such an application, nor is it the case that all aspects of a single DSL can be sensibly represented in a graphical manner; a combination of graphical and textual could be the best solution. This chapter explores the capabilities of the Graphical Modeling Framework (GMF) project, first covering some basics of designing a graphical notation.

4.1 Design Considerations

You must consider many things when selecting a graphical concrete syntax (notation) for a DSL, including scalability, information density, and semantic interpretation of your notation. You can find many examples, both good and bad, from existing notations to use as a guide, although some of the best notations might not yet have been realized, given the restriction that we typically work in just two dimensions. This section gives you some idea of how to best represent your DSL using a graphical notation.

4.1.1 Notation Design

Most people are familiar with the work of Edward Tufte (/www.edwardtufte.com/) on the visual display of information. Although Tufte originally focused on the display of data, many of the concepts he presented can apply to the development of a graphical notation for your DSL.

If you’ve read Tufte’s books or attended his lectures, you know that he recommends that everyone use 30-inch monitors or better. Being confined to an undersized, low-resolution monitor will kill your dreams of effectively modeling any domain using a diagramming surface. The human brain is capable of processing a large amount of high-density information, more so than we are likely to display using the current 2D limitations of our underlying Graphical Editing Framework (GEF) infrastructure. A proposed addition to GEF promises to provide support for 3D, which should introduce an opportunity to improve, yet complicate, the current situation.

One of Tufte’s key messages is to not include gratuitous or redundant notational elements in your display of information. For example, consider the Unified Modeling Language (UML) use case diagram. Actors are associated with use cases, yet each actor is represented by a stick figure along with a role name label. Typically, the stick figure is larger than the label. Why not just have the text label indicating the role name and a link representing its association? Why do we need the stick figure at all? Or, if we must have a graphic, why not a simple label icon? Because the stick figure is typically the same for all actors, no additional information is conveyed, and because the only other main figure is the use case oval connected by a line, it would not be hard to distinguish role names from their associated use cases. The point is, we should strive to eliminate “noise” when designing a graphical notation. Just because we have nifty tools such as GMF to produce graphical notations doesn’t mean we should abandon these basic principles. Arguably, GMF’s default settings should produce “clean” diagrams instead of illustrate all its bells and whistles. Another example to consider when designing your notation is the Ecore diagram and several diagrams like it that use icons to adorn each attribute and method. In the absence of a distinguishing characteristic that indicates visibility, cardinality, or navigability, simply including an icon for these elements is gratuitous. Icons do provide a degree of visual appeal (“eye candy”) for the diagram, but there should always be an option to hide such elements.

The book The UML Profile for Framework Architectures, by Marcus Fontoura, et al., offers a published example of how to improve the density of information of a UML class diagram. In the book, an alternative display of inheritance information is added to a class to indicate either a flattened or a hierarchical representation. Instead of simply adding a static icon for an attribute or method, a box is colored and positioned near each feature to denote visibility, refinement, abstraction, and so on. It’s a powerful visual effect that would be straightforward to implement using GMF.

Inlining graphics and text is another recommendation from Tufte, inspired at least in part by Galileo’s records of observed astronomical phenomena. Galileo included small, text-sized images of his observations within the sentences. Tufte’s sparklines are another example of inlining graphical information within text. In designing graphical notations, consider including text and graphics in ways that leverage this method of enriching the display of information. For example, consider how metric data could be added in the form of a sparkline to a UML class element.

Color is another powerful aspect to consider when designing a graphical notation. Today color printers are common, which supports more use of color in notation, without the redundant use of text or other means of indicating the same meaning. This book illustrates the use of color in the sample business domain diagram, as inspired by the book Java Modeling in Color with UML, by Peter Coad, et al. The book quotes Tufte and others in a discussion on the proper use of color, stressing the importance on its thoughtful application and advising against using too many colors. In general, two to four colors is best. A gradient range of a single color on some diagrams can be effective because it is sometimes difficult to decide on colors to distinguish elements when there is no natural analog to consider. For example, in the book Object-Oriented Metrics in Practice, by Michele Lanza and Radu Marinescu, metric values of classes are displayed using degrees of darkness, making certain elements come to immediate focus. Other measures determine the relative size and shape, resulting in a powerful visual effect.

In summary, you must consider many aspects when designing a graphical notation. Many good examples—and many poor examples—exist. Most people can tell the difference, although you definitely should take into account advice from Tufte and other recognized experts, along with feedback from your Practitioners, of course.

4.1.2 Filters and Layers

A diagram that displays all the information about a model isn’t likely very readable. We’ve all seen large, complex models with hundreds or thousands of nodes and links that end up looking like a Rorschach inkblot test. The overview, zoom, and printing of large wallpaper diagrams can do only so much to help you understand such models. We need ways to filter out information that is unnecessary or not of interest. UML diagramming tools have some familiar filters, where various levels of detail are shown in Class diagrams, for example. Analysis-level detail typically includes only element names, while an implementation view includes visibility, multiplicity, and type information.

The Mylyn project at Eclipse provides a capability to filter out “noise” in an Eclipse workspace based on what the developer is actively working on. Tasks are associated with workspace elements that remain visible, while other elements are dimmed or hidden altogether. Some discussion regards the application of Mylyn technology to diagrams, although nothing has yet been developed. Contributions to this area would be welcome because extending this metaphor to modeling in general has great potential.

GEF provides layering in diagrams, although not much has been done to exploit this mechanism to “lift” or “lay down” information on a diagram, as was done historically with transparencies using overhead projectors and today with presentation animation effects. We need a more well-defined way of defining diagrams of multiple layers, which could come in handy when considering the decoration of models as they move from more abstract to more concrete during model-driven software-development scenarios. This and other ideas to improve the filtering and rationing of information presented on a diagram are points to seriously consider when defining your notation, along with an effective layout algorithm.

4.1.3 Layout

Arguably, the most important factor in providing usable diagrams is layout. Layout algorithms are numerous and can be tuned to suit a specific notation, although sometimes custom layouts must be developed. Keep in mind that fixed or semifixed layouts might be the best option for certain types of diagrams. Our mindmap diagram uses an automatic layout because the last thing the Practitioner wants to do while rapidly brainstorming is stop to adjust the position of a topic using the mouse. At the same time, class diagram layouts are fairly mature but still cannot suit the needs of each modeler, so this requires the capability to adjust the position of diagram elements. Not many modelers would be satisfied with a fixed-layout class diagram.

Links cause the difficulty in layout, in most cases. Links that cross are often considered bad form, yet jumps in links that cross are not a great solution, either. Consider using ellipses (…) to show that a link exists but is not shown until selected or after a filter is removed. Another possibility is to make visible certain types of links during mouseover events, allowing a diagram to easily be viewed in detail but only when desired.

4.1.4 Synchronization

Layout can go a long way toward making diagrams more readable and can even convey semantic information. Keep in mind that diagrams represent a view of the underlying model. In the case of large, complex models, it’s often best to have multiple diagrams, or views, of the model. You can use filters to accomplish these views, as mentioned earlier, or the views can be distinct diagram instances that the Practitioner creates. The question of synchronicity comes up frequently at this point because sometimes we want the diagram to update automatically based on changes to the underlying model, sometimes we want changes to be made only manually, and sometimes we want a hybrid approach in which elements on the diagram should update but no new elements should be added. We explore synchronization options in GMF in Section 11.4.4 “Synchronized.”

4.1.5 Shortcuts

Toward the goal of creating specific views of our model, we often need to create shortcuts, or aliases, of model elements on diagrams that are essentially imported from another diagram or model. Support for shortcuts on diagrams is common, as is the capability to have more than one notation element represent the same underlying domain model element. We explore these options as we develop our sample diagrams. Shortcuts are supported in diagrams generated with GMF and are covered in Section 11.4.4 “Contains Shortcuts To and Shortcuts Provided For.”

4.2 Graphical Modeling Framework

Before GMF, many had undertaken the task of binding the model aspect of the GEF’s Model-View Controller (MVC) architecture to an EMF model. An IBM Redbook was written [43], a sample was provided by the GEF project, and numerous commercial and academic institutions implemented solutions, some of which included a generative component. GMF came about as the result of this need for an easier way to develop graphical editors using GEF and an underlying EMF model.

Today GMF consists of two main components: a runtime and a tooling framework. The runtime handles the task of bridging EMF and GEF while providing a number of services and Application Programming Interfaces (API) to allow for the development of rich graphical editors. The tooling component provides a model-driven approach to defining graphical elements, diagram tooling, and mappings to a domain model for use in generating diagrams that leverage the runtime.

4.2.1 GMF Runtime Component

GMF has two runtime options. The first is commonly referred to as just the runtime; the second is referred to as the “lite” runtime. The former provides extensive capabilities for extension, and the latter focuses on providing a small installation footprint and is largely generative. These two runtimes represent two distinct philosophies of how to provide a diagramming runtime. Even more fundamentally, perhaps, they illustrate two approaches to Model-Driven Software Development (MDSD) in general.

The full runtime was originally developed as an extensible framework for creating diagrammatic editors on Eclipse Modeling Framework (EMF) and GEF. This runtime was originally designed and developed to provide rich extensibility options for clients. It includes a rich set of APIs, extension-points, a service layer, and many enhancements to the underlying EMF and GEF runtimes. The full runtime can be used with or without the tooling and generation features of GMF. The default target of the tooling and generation component is the full runtime.

Details on the GMF runtime, its APIs, and extension-points are described in Chapter 10, “Graphical Modeling Framework Runtime.” Although it’s not necessary to understand the inner workings of the GMF runtime during the initial phase of development using the tooling and generation component, you will eventually need to provide functionality that goes beyond what is generated.

The GMF Lite Runtime

Whereas the full runtime provides a rich published API, numerous extension-points, a service provider layer, and more, the lite runtime is just the opposite. The motivation for the lite runtime was to provide as much of a generated implementation for diagramming as possible, with a minimal runtime code base. The current implementation of the lite runtime consists of a single runtime plug-in, with a single extension-point for supporting diagram shortcuts.

To provide compatibility with GMF diagrams created for the full runtime, the lite runtime uses the same notation model. In theory, a diagram produced with an editor generated using the lite runtime option will open in an editor generated to the full runtime. Some missing features in the lite runtime prevent full interoperability, but it does work, to an extent.

To target the lite runtime when using the tooling, you must first deselect the Utilize Enhanced Features of the GMF Runtime and Use IMapMode options when creating the generator model. When generating diagram code from the generator model, use the Generate Pure-GEF Diagram Code option.

The lite runtime requires a single org.eclipse.gmf.runtime.lite plug-in for deployment, along with its dependencies, which include the Eclipse platform core, EMF, GEF, EMF Transaction, and tabbed properties view. Although it is not as feature rich as the full runtime, it offers a core set of runtime capabilities, including diagram properties, preferences, shortcuts, and validation. For tooling, the lite runtime has its own set of Xpand templates for generation, found in the org.eclipse.gmf.codegen.lite plug-in, available in the GMF Experimental SDK feature.

4.2.2 GMF Tooling Component

As you will see, GMF was itself developed as a DSL Toolkit. From the beginning, it was decided that the tooling for GMF would be as model driven and bootstrapped as possible. In short, a diagram is defined using a collection of models (DSLs) that drive code generators targeting either the full runtime or the lite runtime. One of the remaining tasks to complete the story is to use Query/View/ Transformation (QVT) in the transformation from its mapping model to generation model, to considerably improve the extensibility of GMF’s tooling.

Figure 4-1 illustrates the main components and models used on the tooling side of GMF. To begin, a GMF project is created and references a domain model. A graphical definition model designs the figures (nodes, links, compartments, and so on) that will be used to represent domain model elements on the diagram surface. A corresponding tooling definition model supports palette tool definition and other tooling for use in diagramming. The mapping model binds elements from the graphical and tooling definitions to the domain model. A transformation from the mapping model to the generator model is followed by the generation of a diagram plug-in.

Note that it is possible to design and run GMF diagrams without a domain model, which can be useful for those who want to experiment with notation design and not be burdened with mapping it to a domain. Each of these models is described in some detail in the following sections, and Chapter 11, “Graphical Modeling Framework Tooling,” includes a complete reference for each model. Following the basic overview of each model, we turn to learning more about them in the context of developing our sample application diagrams.

Graphical Definition Model

The graphical definition model consists of two parts and defines the graphical elements found on a diagramming surface. The first part is a Figure Gallery, which defines figures (shapes, labels, lines, and so on) that the Canvas elements later reference to define nodes, connections, compartments, and diagram labels. An important point is that figure galleries can be reused. Many diagrams require similar-looking elements, such as a rounded rectangle with center label, or connections that are a solid line with open arrowhead decoration on the target end. Defining a number of figures and sharing galleries within your organization or larger community means less time spent reinventing the wheel. For UML2, a set of figures are defined and available for reuse from the UML2 Tools component of the Model Development Tools (MDT) project.

Figure 4-1 Graphical Modeling Framework workflow

Image

The mapping model references figures defined in the gmfgraph model. When the mapping model is transformed to the generator model, figure code is generated and included within the gmfgen model itself. When code is generated, edit parts will contain figures as inner classes. This is the default behavior when working with GMF, although it is not necessarily the recommended approach.

Another lesser-known feature of the graphical definition model is the capability to export figures to a standalone figure plug-in. This can also satisfy reuse because these plug-ins can be shared by several diagrams and among a community as a binary form of the figure gallery. To create a figure plug-in from a gmfgraph model, either use the Generate Figures Plug-In context menu action, or start by creating a new plug-in project and select the Figure Definitions Converter template in the plug-in project wizard. Section 4.5.5 “Generating the Figures Plug-In,” covers the use of a standalone figure plug-in.

A complication that arises when using a standalone figures plug-in is that it creates a “mirror” of the gmfgraph model. This adds one more model to the picture that needs to be synchronized, so it’s recommended that you first define all your figures and generate the plug-in that contains the associated mirror.gmfgraph model. The mapping model uses the mirrored model instead of the original graphical definition model. With this approach, the mapping model passes class name references to the generator model, not actual classes. The generated code simply references the figure classes in their own plug-in and is not written out as inner classes within generated edit parts. This process imposes the additional step of regenerating the figures and mirrored model upon a change to the graphical definition. A future version of GMF will hopefully do away with the serialized class method and make generating a standalone figures plug-in work more seamlessly in the workflow.

To ease the design of figures, a WYSIWYG (what you see is what you get) style of editor is included in the experimental Software Development Kit (SDK). It is not complete, but it illustrates the bootstrapping of GMF and a method for customization using a decorator model described in detail in Section 4.2.2 “Dynamic Templates.” Use of the graphical model editor is also helpful for understanding layouts and how they work when composing complex figures.

Tooling Definition Model

Diagrams typically include a palette and other periphery to create and work with diagram content. The purpose of the tooling definition model is to specify these elements. The tooling model currently includes elements for the palette, the toolbar, and various menus to be defined for a diagram. Unfortunately, in the current release of GMF, the generator uses only the palette element. If additional capabilities are required until this functionality is completed, advanced properties view UI elements can be designed using an extension to the generator model and custom templates, as discussed in Section 4.6.6 “Color Preferences.” Note that it is also possible to exclude the palette altogether from a diagram definition, thereby creating a read-only diagram. Of course, the pop-up bars and connection handles features should be disabled as well in this case.

Mapping Model

Perhaps the most important of all models in GMF is the mapping model. Here, elements from the diagram definition (nodes and links) are mapped to the domain model and assigned tooling elements. The mapping model represents the actual diagram definition and is used to create a generator model. Typically a one-to-one mapping exists among a mapping model, its generator model, and a particular diagram.

The mapping model uses Object Constraint Language (OCL) in many ways, including initializing features for created elements, defining link and node constraints, and defining model audits and metrics. Audits identify problems in the structure or style of a diagram and its underlying domain model instance, and metrics provide measures of diagram and domain model elements.

Generator Model

As mentioned in the overview, the generator model adds information used to generate code from the mapping model and is somewhat analogous to the EMF genmodel. Both can be reproduced and reloaded from their source models, although the EMF genmodel is a true decorator model. The GMF generator model is more of a many-to-one model transformation than a decorator model.

As a mapping model is transformed into a generator model, it loses knowledge of the graphical definition and gains knowledge of the runtime notation model. This minimizes the number of dependencies linked from the generator model and separates concern among the models. Currently, the transformation is performed using Java code, but it is planned to be reimplemented using QVT to give Toolsmiths easier customization, as mentioned earlier.

A trace facility exists in the experimental SDK to aid in generating visual IDs when new nodes are added and the generator model is updated. A reconciler preserves other user-modified elements in the generator model upon retransformation from the mapping model. Many of the commonly modified properties are preserved, although not all of them are, so be aware of this when making changes to the generator model.

As with EMF, you can use custom code-generation templates in GMF. The main difference here is that EMF uses Java Emitter Template (JET) as its template engine, and GMF uses Xpand. Chapter 14, “Xpand Template Language,” covers Xpand, which also is used throughout Chapter 7, “Developing Model-to-Text Transformations.” You can find information on how to use dynamic templates in GMF in Section 4.2.3, “Dynamic Templates,” and in our sample diagram in Sections 4.34.6.

When using the full runtime as a generation target, a number of extension-points are contributed to in the generated diagram code. You will likely want to explore the generated plug-in manifest and source code.

4.2.3 Customization Options

You can extend the GMF generator in several ways, all of which are analogous to how you can use and provide for extensibility in your DSL tooling. The next sections discuss code modification, extension-points, dynamic templates, and decorator models, and illustrate them in the sample applications.

Code Modification

As GMF utilizes JMerge to protect Toolsmith modifications of generated code from being overwritten, the same practice of placing NOT after @generated tags in code can be used as with EMF. Additionally, GMF provides merge capabilities for plugin.xml and MANIFEST.MF files, which is a nice feature that EMF should consider adopting.

Extension-Point

When targeting the full runtime for generation, provided extension-points can be used to extend diagrams generated using the tooling component of GMF. This approach has the benefit of being completely separate from the generated diagram and code. For example, a parser provider for our color modeling diagram’s attribute elements is provided in this manner, as discussed in Section 4.6.6, “Custom Parsers.” The service-provider aspect of the runtime allows for the addition or overriding of behavior in diagrams, such as the addition of EditPolicies to an EditPart, as illustrated in Section 10.9.3, “Custom EditPolicy.”

Dynamic Templates

Also as in EMF, you can leverage dynamic templates to provide customized output from GMF code generators. You can extend or override both the templates used to generate figure code and the templates used to generate diagram code using so-called dynamic templates.

GMF uses Xpand extensively. To override a template for diagram generation, you must put it in the same directory structure (namespace) that GMF uses. The easiest way to see the templates and their structure is to import the org.eclipse.gmf.codegen plug-in into your workspace using the Import AsSource Project option from the Plug-Ins view. Note also that GMF templates contain ≪DEFINE≫ entries for extraMethods and additions with corresponding ≪EXPAND≫s to allow for extensibility. When using the ≪AROUND≫ construct for aspect-oriented features of Xpand, GMF requires placing these templates under an /aspects folder below the root in order to be found. GMF recently added a new “composite template” approach that makes it possible to augment an existing template if found in the same namespace, effectively merging its content with the original. Sections 4.6.5, “Gradient Figures,” and 4.6.6, “Color Preferences,” describe the use of custom templates with GMF in detail.

Decorator Model

A more advanced—and possibly most conceptually “pure”—method for customizing or extending the output of GMF code generators is to use a decorator model. Basically, the GMF generator model is wrapped in a root XML Metadata Interchange (XMI) element to allow additional decorator model instances to coexist and to enable elements of the generator model to reference them. Xpand templates used to generate diagram code are augmented with custom templates that are invoked when these references are encountered.

The GMF graphical definition model has a bootstrapped diagram editor to allow for WYSIWYG-style figure development. It was implemented using custom templates and also includes a decorator model for use in defining its form-based properties view. This serves as an example of how to use decorator models in the context of GMF, but also for any other occasion in the context of using a DSL Toolkit where extensions are required to an existing model used for generation. Section 4.6.6, “Color Preferences,” covers the steps in using decorating models in GMF.

Model Extension

With the addition of the child extenders feature in EMF 2.4, it’s possible to have your contributed model elements of customizations to the GMF models available in the default editor. GMF 2.1 has been regenerated with these generator model settings, thereby allowing your extensions to contribute to GMF editors. The UML2 Tools project has extensions defined for GMF models and makes use of this new capability.

4.2.4 Dashboard

GMF comes with a dashboard view that streamlines the workflow of dealing with its collection of models. The dashboard is available from WindowShow ViewOtherGeneralGMF Dashboard (Ctrl+3 → gmfd), or you can open it when creating a new GMF project. Figure 4-2 shows the dashboard used in the context of the mindmap diagram sample project.

Figure 4-2 GMF Dashboard view

Image

Each model can be selected, created, or edited within the dashboard, including EMF *.ecore and *.genmodel models. Invoking GMF and EMF wizards is accomplished using the hyperlink actions throughout, making the dashboard helpful not only in understanding the workflow, but also in streamlining the invocation of transformation and generation actions during diagram development.

4.2.5 Sample Application Diagrams

The best way to learn how to use GMF is by example, as with most new technology. The following sections explore most aspects of GMF-based diagram definition in the context of our sample projects, by design. Comments throughout should illustrate the techniques for developing diagrams, enumerate their relative pros and cons, and provide the basis for becoming well versed in GMF tooling.

Because diagramming is central to mindmaps, I pay special attention to this diagram, particularly layout and other usability elements. The requirements dependency diagram is similar to the mindmap, but the underlying model structures are different, so we explore how this impacts our mapping model. The scenario diagram enables us to explore the concept of diagram partitioning. Finally, our business domain modeling diagram explores compartments, customization, and more advanced labeling techniques.

4.3 Developing the Mindmap Diagram

Our diagram for the mindmap DSL defined earlier is rather straightforward: It is a simple “box and line” style of diagram, but one that serves us well in introducing GMF. We start out with a simple default diagram definition to first understand the basics, and then we iterate through several enhancements, including layout and advanced figures.

4.3.1 Mindmap Graphical Definition

Building on Section 3.3, “Developing the Mindmap Domain Model,” you should have a mindmap DSL project and the generated EMF plug-ins from the mindmap domain model in your workspace. We put our GMF models in the diagrams folder, so begin by right-clicking that folder and selecting NewOtherModelsGraphical Definition Model and naming it mindmap.gmfgraph. If you’re not using the DSL Toolkit, you’ll find the standard GMF wizard in NewOtherGraphical Modeling FrameworkSimple Graphical Definition Model. Use Find in Workspace to quickly locate our mindmap.ecore model and select Map as the Diagram Element. The next page of the wizard presents elements discovered within the domain model and a guess at what would be appropriate for each: node, link, label, or nothing. Make the dialog look like Figure 4-3 so that we’ll create a node for the Topic element with a label for its name attribute and link for subtopics, and a link for the Relationship element with labels for its name and type. Finally, click Finish.

Figure 4-3 Graphical Definition Wizard

Image

The model derived from the wizard has a canvas named mindmap, a node for our Topic element, two connections, and three labels. Each corresponds to an element in the figure gallery. For now, we don’t modify what the wizard has produced because we first want to get through the entire process. Later, we’ll come back and refine the graphical definition.

4.3.2 Mindmap Tooling Definition

Similar to the process of examining the domain model to produce a starter graphical definition, a wizard enables you to create a tooling definition model, as seen in Figure 4-4. Begin again by right-clicking the diagrams folder and navigating to NewOtherModelsTooling Definition Model ; name it mindmap.gmftool, locate the mindmap.ecore model, and select Map as the Diagram Element. The wizard should correctly determine the required tooling: a node tool for the Topic element, and link tools for both the Relationship element and the subtopics relationship within Topic. Deselect the link suggested for the parent reference.

Figure 4-4 Tooling Definition Wizard

Image

With the tooling model open in its editor, you can see that the wizard created a single tool group and creation tools for each of these. We might want to create separate groups for links and nodes, but for now we’ll leave the model as is.

4.3.3 Mindmap Mapping Model

Once again, we use a GMF wizard to get us started. Right-click on the diagrams folder and select NewOtherDomain-Specific LanguageDiagram Definition to begin creating a GMF mapping model. Note that you can begin a diagram definition directly from this wizard because it enables you to create a new palette model and select an existing graphical definition model. Provide the name mindmap.gmfmap and select Map as the class to represent the canvas. Accept the default mindmap.gmftool model and select our mindmap.gmfgraph model on the next page. On the Mapping page, modify the wizard defaults and move Relationship to the Links list, leaving just Topic in the Node list. Remove all but subtopics and Relationship from the Links list, as shown in Figure 4-5.

Figure 4-5 Mapping Model Wizard

Image

Notice that for each selection of Node and Link, you can change the wizard’s mapping. A limitation on Nodes exists: The dialog that displays with Change shows only the mapping for the top-level node, not the node mapping or labels. Try this now with the Relationship link, setting the Source Feature to the source reference and the Target Feature to the target feature. Also ensure that the proper Tool and Diagram Link are selected. Upon Finish, browse the mapping model in the editor. Check each property to verify that all are correct, and use the Validate action from the context menu.

Regarding our two types of links, notice that they illustrate the two most common methods of providing link mappings for a diagram. The subtopics reference maps to a link that shows the relationship between Topic elements. In this case, we need to indicate only the Target Feature in our link mapping, leaving the other properties blank. The relationship link shows how to map a link to a domain model class—in this case, our Relationship class. To complete the mapping definition, we need to specify the Element and its Containment Feature, Source Feature, and Target Feature for the link.

Let’s go through the mapping model in some detail, because it often causes confusion. Beginning with the Canvas Mapping element, you can see that the Map domain Element will be represented by the mindmap Diagram Canvas from our mindmap.gmfgraph model. Similarly, the diagram canvas will have a Palette, represented by our mindmap.gmftool model’s mindmapPalette element. Note that the Menu and Toolbar Contributions properties are blank because GMF has not yet implemented them, as seen in Table 4-1.

Table 4-1 Mindmap Canvas Mapping

Image

For our Topic node, we see in the properties of the Top Node Reference

that new instances of Topic elements are to be maintained in the elements containment reference of our Map class, as shown in Table 4-2. The Children Feature property is left blank because we retrieve and store our Topic

elements directly from the elements containment feature.

Table 4-2 Mindmap Topic Mapping

Image

Below the Top Node Reference mapping is the Node Mapping for the Topic class itself. The Topic class, which is a subclass of MapElement, is used for the node’s Element. The Topic node from our mindmap.gmfgraph is used for the Diagram Node, which we see references the TopicFigure from the Figure Gallery. Finally, the Node requires a Tool, so we select the Topic Creation Tool from our palette defined in our mindmap.gmftool model. Note that the Appearance Style and Context Menu properties are left blank because GMF has not yet implemented them.

The Topic displays its name using a label, which is defined in the child Feature Label Mapping element. The Diagram Label property is selected to the TopicName label in our graphical definition and displays the value of the Topic’s name:EString attribute. Both the Edit and View Method properties are set to the default MESSAGE_FORMAT value, meaning that the Java MessageFormat class provides the underlying implementation for parsing, editing, and displaying our label. In the case of our Topic label, a single attribute is displayed, with no other characters required.

With the node mapping complete, let’s look at the subtopics link mapping. In our domain model, Topics are related to other “sub” Topics using the subtopics reference. Simple references such as this are straightforward to map in GMF because we only need to set our Target Feature property to this reference in our domain model, as seen in Table 4-3. Our next link mapping discusses the remaining Domain meta information properties. The Diagram Link and Tool properties are set as you would expect, to the TopicSubtopics Connection from our graphical definition, and to the TopicSubtopics Creation Tool in our tooling definition, respectively.

Table 4-3 Mindmap Subtopic Link Mapping

Image

The Relationship Link Mapping is more involved than our TopicSubtopics Link Mapping because we are mapping a domain class to the link, not just a reference within a class, as seen in Table 4-4. In this case, the Relationship class in our domain model is the domain Element, with the element’s Containment Feature of our Map being where we will store new Relationship instances created with each link. Using a class to represent a relationship in our domain model essentially gives us what an EAssociation in Ecore itself would provide. The Source and Target Feature properties map in a straightforward manner to our source: Topic and target: Topic references, respectively. As with the TopicSubtopic link mapping, we map our Diagram Link and Tool properties to their corresponding graphical and tooling model elements. Again, Appearance Style and Context Menu go unused; Section 4.5, “Developing the Scenario Diagram,” discusses the Related Diagrams property.

Table 4-4 Mindmap Relationship Link Mapping

Image

Image

The graphical wizard created child label figures for our relationship link, but the mapping wizard does not provide label link mappings. We need to add these manually before proceeding. Create a new child Feature Label Mapping to the Relationship Link Mapping and fill in accordingly, for the Relationship name attribute.

Add another Feature Label Mapping to the link, but this time set it to Read Only and alter the View Pattern to add ≪guillemets≫ to the type name. With the basics of our initial diagram mapping understood, we’re ready to move on to generation.

4.3.4 Mindmap Generator Model

The last model to create in developing our mindmap diagram is the GMF generator model. As mentioned, this model is analogous to the EMF genmodel and contains additional parameters used for generating our diagram plug-in. Technically, the GMF generator model is a bit more complex and is really the result of a many-to-one model transformation. To produce our mindmap.gmfgen model from our mindmap.gmfmap model, right-click the mapping model and select Create Generator Model to open the wizard. The default name and location are fine, as is the selection of the mapping model. The mindmap.genmodel should also be selected by default but could indicate a warning about the relative date of the genmodel to its ecore model. If required, reload the genmodel at this time; GMF utilizes references found there for its own code generation. On the last page of the wizard, leave the defaults as is and click Finish to complete.

Open the new mindmap.gmfgen model in the editor so we can adjust a couple of its properties prior to generation. In the Gen Editor Generator properties, set the Diagram File Extension to mmd in place of the default mindmap_diagram, as seen in Figure 4-6. Also, we select true for the Same File For Diagram and Model property. The default behavior persists them into separate files, which we consider for other diagrams.

Figure 4-6 Mindmap GMF generator model

Image

At this time, we leave the remaining defaults for the generator model and generate code by right-clicking the mindmap.gmfgen model and selecting Generate Diagram Code. A new org.eclipse.mindmap.diagram plug-in appears, and because we already have a launch configuration from our domain model, all we need to do is run.

A wizard is generated for our mindmap diagram, which we use to create and populate a simple map. Figure 4-7 is an example of what you can see and do at this point.

Figure 4-7 Mindmap initial diagram

Image

Now that we’ve proven that we can quickly create a basic diagram to allow for graphical editing of our DSL, let’s go back and explore in detail more of the options available using GMF.

4.3.5 Improving the Mindmap Diagram

So far, we’ve used the default settings that GMF provides and have established that everything is working. Now let’s go back and refine our models to get closer to what we want from our mindmap diagram. The label icons are superfluous, as are the full rectangles for our subtopics, so let’s begin by improving our notation elements and regenerating the diagram. Before completing this section, you might want to review the GMF tooling models described in Chapter 11.

Updating the Graphical Definition

Using our mapping model editor instance and expanding our mindmap.gmfgraph node, create a new Figure Descriptor named TopicFigure in the Figure Gallery. To this descriptor, add a child Rounded Rectangle named TopicFigure. Adjust both the Corner Height and Width properties to 15. Add a Stack Layout to the Rounded Rectangle to center our label in the rectangle. Add a child label named TopicNameFigure, and to keep the label from getting too close to our left and right edges, add an Insets child to the rectangle and set the Left and Right properties to 5. We want to have the default line color set to blue, but we won’t use the Foreground Color elements because we want the default color to be reflected in the diagram preferences. We set default values in our diagram preferences in Section 4.3.3, “Diagram Preferences.”

We can delete the original rectangle figure descriptor assigned to the Node Topic and select our new rounded rectangle descriptor. As with the original TopicFigure, we need to add a Child Access to the Figure Descriptor and set its Figure to our TopicNameFigure. In the TopicName Diagram Label, set the label’s Accessor property to the getFigureTopicNameFigure Child Access created earlier for the Topic’s name label. The label currently has its Element Icon property set to true. This is the default, but because the icon adds no information at this point, it’s just noise; set this property to false, and do the same for the RelationshipType and RelationshipName labels. To provide a reasonable default size for our Topic nodes, we add a Default Size Facet element to its Node element, with a child Dimension element. We give it a default size of Dx = 80, Dy = 40. That’s it for our Topic node.

We also want to change the look of our relationship links. We want to use a dashed line and open arrow decoration on the target for our relationships, and just a solid line with no decoration for our subtopic. Later, we’ll add a circle decoration to the target of our subtopic link, but that requires writing some custom code. For now, change the name of our Polyline Decoration to RelationshipTargetDecoration and select this decoration as the Target Decoration for our RelationshipFigure. Change the Line Kind of our RelationshipFigure to LINE_DASH and remove the target decoration from our Subtopics connection figure.

Table 4-5 shows the current state of the graphical definition; only properties that changed from their default values are shown.

Table 4-5 Mindmap Relationship Link Mappings

Image

Image

Image

Updating the Tooling Definition

Expand the mindmap.gmftool node in the mapping model. We want to have two groups of tools in our palette. The first will have the Topic node creation tool; the second will have our links, including a stack of tools for our different types of relationship links (dependency, include, extend). This is a simple matter to accomplish in our model using copy and paste, with some renaming. The only special property you need to set is the Stack property to true for our Relationships Tool Group. Note that if you want to have each group in a drawer, you must set the Stack property to true. Figure 4-8 shows what your tool model should look like at this point. Note that if a particular tool should be the default one available, you must use the Active property to select it. In our case, the dependency tool is first on the list and is a reasonable default.

Figure 4-8 Mindmap GMF tooling model

Image

Updating the Mapping Definition

The main change we need to make to our mapping definition is to our Relationship link. Our DSL includes a Type enumeration with three literals: DEPENDENCY, INCLUDE, and EXTEND. We now have three separate tools for these relationship types, so we need to create a mapping for each. Begin by modifying the existing relationship link mapping to be our dependency link, and then copy/paste the element and adjust for the include and extend mappings. Table 4-6 shows what the dependency mapping looks like after our changes.

Table 4-6 Updated Mindmap Relationship Link Mapping

Image

As you can see, the link mapping now has some additional child elements. First, we add a Constraint to indicate using OCL that self.type = Type::DEPENDENCY. This enables us to identify each of our Relationship mappings so that the generator can create code to distinguish nodes based on their type attribute. Also, we add a Feature Seq Initializer child element along with Feature Value Spec and Value Expression that sets the value of the type attributes upon link creation.

At this point, we only need to copy/paste the dependency link mapping and alter the properties accordingly for INCLUDE and EXTEND links. When complete, validation and update of the generator model from the mapping model, followed by code regeneration, will enable us to run and test our updated diagram. This will become a familiar sequence, which begs for the creation of a single action to streamline the process. The Dashboard view comes in handy for this purpose.

Topic Figure Layout

Before we run the diagram, we need to make some tweaks to the generated code if we want our Topic name labels to be centered in their rounded rectangle and wrap. The code we use is from the GeoShapeFigure class in the runtime. In the TopicEditPart class, adjust the constructor for the inner TopicFigure class as follows:

image

To allow our WrapLabel to wrap, we need to slightly modify the createContents() method as follows:

image

Figure 4-9 shows our diagram. Note the relationship stack of tools in the palette and note that the mindmap.ecore literal values for our relationship Type enum have been changed to lowercase. Alternatively, we could have changed the case within our label code, or even shortened the literal values to be just d, e, or i.

Figure 4-9 Mindmap relationship links

Image

Adding Custom Layout

A major requirement for a mindmap diagram is good layout, preferably automatic. A fixed layout is fine for our needs, although more advanced layout strategies that are pseudo-fixed are possible. Mindmaps should be arranged in a tree, typically with both left-to-right and right-to-left flows to the sides of the central Topic. The default layout for GMF-generated diagrams is top-to-bottom. The layout we need is similar, if you consider that mainly the orientation of the layout needs to be changed from vertical to horizontal. This is exactly what the GMF runtime’s LeftRightProvider class provides, so we use it as a starting point.

We could add the following modifications to our generated diagram plug-in, but as mentioned earlier, this would make regeneration and maintenance more difficult. Instead, here we create a new org.eclipse.mindmap.diagram.custom plug-in project using PDE and put our modifications in this separate plug-in.

Let’s back up a minute and discuss the big picture of diagram layout and our needs for the mindmap. You’ve seen that the main toolbar for all GMF diagrams has a layout button, with a corresponding context menu on the diagram canvas. The runtime provides these by default for all diagrams, so it’s a matter of adding our own provider for the layout service to invoke. We begin with the layoutProviders extension-point and contribute the following to our plugin.xml manifest. Section 10.4.4, “Layout Service,” discusses the layout service.

<extension point=”org.eclipse.gmf.runtime.diagram.ui.layoutProviders”>
   <layoutProvider class=”org.eclipse.mindmap.diagram.layout.
    MindmapDefaultLayoutProvider”>
    <Priority name=”Low”/>
   </layoutProvider>
</extension>

We’ve set the priority of our provider to Low, which is one level above Lowest. Now we need to implement the MindmapDefaultLayoutProvider, as shown here:

image

As you can see, our default provider simply extends the runtime-provided LeftRightProvider and only needs to override the provides() method to enable our provider for mindmap diagrams. We’ll further modify this provider later to get the layout we want, but for now, this is all we need to get started. Besides the need to provide both left-to-right and right-to-left layout of topics about a centered root, we want to ignore dependency links when performing a layout. More specifically, we want to lay out topics in a tree structure while arranging relationship links to avoid topics; relationship links will be optionally hidden and should not be considered during main layout.

When deployed, this provider replaces the default layout provider that the menu item and toolbar invoke. Section 4.3.3, “Subtopic Figure,” explores what is required to programmatically invoke layout on a diagram as we create subtopics using a keyboard shortcut.

Subtopic Figure

For our notation, we want root Topic elements to be displayed with a rounded rectangle, and subtopic elements to be displayed with a single underline. Our domain model has no notion of distinct Topic and subtopic elements, so this means we end up with two figures for the Topic element that will change depending on the structure of the elements. Furthermore, we might decide that n-level subtopic elements should have yet another notation, so we focus on a solution that is general. Currently, the models of GMF cannot handle this type of definition, whereby a different figure represents a domain element based on its state. This is a planned enhancement for GMF, but in the meantime, we begin by adding a new subtopic figure.

The subtopic figure is a rectangle with only the bottom border drawn, thereby appearing as an underline for our subtopic name. The makeup of this figure is somewhat complicated. Table 4-7 details our subtopic figure and node properties. Note the use of CustomBorder, which uses a provided runtime figure.

Table 4-7 Mindmap Subtopic Figure

Image

Our tooling model does not require changes because we don’t want to allow for the explicit creation of subtopic nodes; we want to have them visualized when subtopic links are made. Our mapping model needs a new top-level node mapping, as shown here along with our original Topic mapping. With two node mappings for a single domain model element, we need to define a constraint for each so that the generated code can distinguish between them, as seen in Table 4-8. This is especially important when diagrams are created from existing models, to remove ambiguity and to allow for the proper notation to be assigned. In the case of our mindmap, Topic elements with no parent are considered “root” Topics and use the rounded rectangle figure. Those that have a parent, which is the eOpposite of the subtopics reference, will be rendered with our new underline figure.

Table 4-8 Updated Mindmap Node Mappings

Image

Regenerating our diagram and testing reveals some problems. Although it’s possible to create subtopic links, the target figure is not immediately updated. If we use the provided refresh action by pressing F5, we see that the figure updates and its location is preserved. If we create a relationship link, the diagram is refreshed automatically because of the canonical update of the Map itself. We want the image to automatically update when a subtopic link is created or removed, and for layout to be invoked when using the palette or an action. As with most things in GMF, we can solve our problem in many ways.

If we look at our MapCanonicalEditPolicy class, we see the refreshSemantic() method, which is invoked by our refresh action. The generated code overrides this method and the isOrphaned() method from CanonicalConnectionEditPolicy to incorporate knowledge of our mapping constraints into the logic. If you look into the code, you’ll see that view elements that have no corresponding semantic element are deleted, while semantic elements with no view have one created. As soon as a subtopic connection is made between two Topics, our constraints prompt the deletion of our target Topic view because its visual ID no longer matches its semantic constraint. We could override the methods in this EditPolicy and its superclass to transfer the location of the original view to the updated view. This is feasible but would require the copy and paste of a lot of code because many of these methods are marked as final in the runtime.

Another option is to implement our own connection tool used in the palette that could invoke a delete-and-create-view-command to update our Topic figure after link creation. This would not solve our problem of switching the view back when the subtopic link is removed, although it would be a clean way of creating an updated figure in the same location. This approach is covered in the UML2 Tools project, which provides actions to toggle alternative notations of some UML elements, such as Interface. Specifically, take a look at the ChangeNotationAction class, in the org.eclipse.uml2.diagram.common plug-in. There, the original view element’s location is passed to the create-view-request, to avoid the positioning problem.

We know that the view needs to change when an element is added or removed from a Topic’s subtopics reference list, so we can watch for events on this feature and invoke a refresh on our MapCanonicalEditPolicy. Furthermore, we can add code to the EditPolicy to invoke a diagram layout when subtopics are added, or when Topics are added or removed from the diagram.

In each of our Topic EditParts, we override the handleEvent Notification() method and invoke the refresh() method on our MapCanonicalEditPolicy class, to let the generated code update the view on our Topic elements.

image

In our MapCanonicalEditPolicy class, we override handleNotificationEvent() and look for additions or removals from our Map’s elements feature and invoke a new layout() method. Finally, we modify the refreshSemantic() method to invoke layout if it’s detected that a new view was created in the process.

image

This gets us a lot closer to our desired behavior of having a fixed layout. Certain actions, such as resizing topics manually, represent another opportunity to update layout. For now, we move on to a new topic.

Custom Connection Figure

Although you can define many figures using the GMF graphical definition model, some figures require custom code. Additionally, you might want to reuse existing figures in GMF diagram definitions, as you saw with CustomBorder. To illustrate this capability, here we use a custom figure for the target decoration of our subtopic link. This is the source code for a simple circle figure that we’ll add to a new org.eclipse.mindmap.diagram.figures package in our diagram plug-in:

image

To use this figure, we’ll create a new Custom Decoration in our figure gallery named CircleDecoration with a Qualified Class Name of org.eclipse.mindmap.diagram.figures.
CircleDecoration
. In the Source Decoration property of our TopicSubtopicsFigure, we’ll select this decorator and then regenerate our mindmap.gmfgen model from our mindmap.gmfmap file.

Adding a Subtopic Action

Adding new subtopics to our mindmap is not very convenient right now. The mouse and palette are required to first create a Topic and then a connection, seriously impeding our “brainstorming” ability. We want to use the keyboard as much as possible to add and insert new Topic elements. Adding keyboard shortcuts and menu items to elements involves straightforward Eclipse platform code that we can add to our customization plug-in. Note that here we don’t use the contributionItemProviders extension-point that the runtime provides because of some outstanding issues with keyboard binding at the time of this writing.

First, we add the object contribution to our org.eclipse.mindmap.diagram.custom plug-in manifest, as shown. Only our Topic EditPart classes need the contribution because it makes sense to add a new subtopic only from the context of an existing Topic. The only nodes on our diagram are either Topics or Subtopics, so we use their superclass ShapeNodeEditPart for the objectClass. We’re defining an Insert menu item, with a child Subtopic action. We could have created a single menu item (Insert → Subtopic), but this gives us a placeholder for other possible additions, such as Insert → Parent Topic.

image

The declared action class is MindmapCreateSubtopicAction, which we have defined next. It enables only a single Topic selection because it doesn’t make sense to invoke the action for multiple selected Topic elements. Before diving into the action code, we complete our definition by contributing to the commands and bindings extension-points.

image

We’re using the Ctrl+I (Cmd+I on the Mac) key combination to insert new subtopics, and we’re using the provided edit category for the command. Also note that we are using the contextId that is declared in our generated diagram plug-in for use with the F5 diagram refresh action. This is the implementation of our create subtopic action:

image

Starting at the bottom with the selectionChanged() method, we set our selectedElement field to be that of the currently selected Topic. The run() method of our action class does all the work to create the compound command for creating our new subtopic and associated link, invoking the diagram layout, and finally activating the in-place editor. The code is fairly straightforward, aside from the details of what goes on within the DeferredCreateConnection ViewAndElementCommand when executed. For this, it’s recommended that you set a breakpoint and follow its execution, if interested, as is the case with much of the GMF runtime code.

One troubling point of our implementation are the references to MindmapElementTypes TopicSubtopics_4001 and Topic_2001. These are generated visual IDs that are produced by the tooling of GMF and are subject to change, unfortunately. A better solution here is to create custom templates that would enable us to generate this action and, therefore, eliminate the possibility that our custom action code will break after some future change to the generated diagram code. Section 4.4.4, “ToolTips,” covers the use of custom templates for diagram generation.

Adding Fixed Anchor Locations

By default, connections made between Topics and their subtopics anchor on the target using one of several anchor points. Although this works well for many diagrams, we don’t want this in the mindmap. The situation is helped to an extent by our automatic layout, which nicely anchors links to the right and left of the topics, but that’s not quite where we want them in the case of subtopics. Figure 4-10 is a simple example to illustrate the problem before the layout is added. As you can see, the target decorators are positioned where the default chopbox anchor point is calculated, using the center of the figure as a reference point. This applies to the outgoing source end as well.

Figure 4-10 Mindmap chopbox anchors

Image

Preferably, lines should connect at a fixed point for all Topic elements to the left of the text at the target end. The source end should have the line connect at a point to the right of the text. Following are SourceFixedConnection Anchor and TargetFixedConnectionAnchor classes that you can add to the generated TopicEditPart and Topic2EditPart classes. A root Topic never needs a target anchor: After a subtopic connection is made, the figure changes. We’re going to ignore relationship links from our layout and don’t want them to be anchored the same as subtopic links, so we’re applying our anchors only to subtopic connections. The code we use is basically stripped-down versions of the FixedConnectionAnchor provided with the GEF Logic Diagram example. First, consider the additions to TopicEditPart:

image

The overridden getLocation() method provides the main functionality. To install on our EditPart, we override getSourceConnectionAnchor(), and in our Topic2EditPart, we override getSourceConnectionAnchor() as well.

image

Figure 4-11 shows an updated image of our mindmap that, again, uses our default layout. Clearly, this is an improvement, but we still have some tweaking to do. Note that although the left-to-right anchor and layout have been implemented, we need to modify the implementation if we are to support right-to-left layout as well.

Figure 4-11 Mindmap fixed anchors

Image

Diagram Preferences

Our generated diagram code includes preference settings that are accessible from the Eclipse preference dialog in a Mindmap Diagram category. Diagram general, appearance, connection, ruler, grid, and printing preferences are all available from a set of contributed preference pages. In our generated org.eclipse.mindmap.diagram.preferences package is code that supports further extension and enables us to set defaults. For example, if we want all the mindmap diagram lines to be blue by default, we can adjust our DiagramAppearance PreferencePage class as follows:

image

We can set more preferences and add new preferences. Section 4.6.6, “Color Preferences,” looks at how to modify code-generation templates to add custom preferences for the color modeling diagram.

Audits and Metrics

GMF provides the capability to define OCL-based audits and metrics for the domain and diagram models. Using the mapping definition model, we can define diagram audits and metrics for both domain and notation model elements. What’s generated leverages the EMF Validation Framework. To begin, we open our mindmap.gmfmap model in the editor, right-click on the Mapping element, and add a new Audit Container child. To the container, add the two audit rules in Table 4-9.

Table 4-9 Mindmap Audit Definition

Image

We’ve defined two audits using OCL. The first detects cycles in Topic subtopic relationships using MDT OCL’s closure() iterator. If the topic is within the set of all subtopics, a cycle is formed. The Severity of this audit is set to WARNING and it is not used in Live Mode, meaning that the Practitioner must manually invoke the DiagramValidate menu item to run the audit. The second audit detects invalid Topic names, which, in this case, are limited to empty name strings and those that are not initialized. A more elaborate audit could be created to ensure that valid Topic names are entered. The severity is set to error and the audit is defined as a “live” audit. This means that it will be invoked automatically when changes are made to the specified domain element. As you’ll see in the generator model, an additional option is available to provide immediate UI feedback: A dialog will pop up to alert the Practitioner that the change made violates a constraint.

Moving to metric definitions, right-click the Mapping node again and add a child Metric Container element. Populate the container with the elements and property settings in Table 4-10.

Table 4-10 Mindmap Metric Definition

Image

Metrics are defined with upper and lower limits and are based on the result of the OCL statement. In this case, we’re counting the number of direct subtopics of a Topic. We could define another that counts the total number of subtopics using the closure() iterator we used earlier.

At this point, we can re-create our mindmap.gmfgen model from the mapping model and observe new Gen Audit Root and Gen Metric Container elements. More interesting are the options related to validation in the Gen Diagram element. Under the Diagram category are the Validation Enabled and Validation Decorators properties that we set to true here. Also notice the Live Validation UI Feedback property mentioned earlier. Here we set this to true as well, just to see the result. In the Providers category are a number of additional options related to validation and metric priorities and providers. The Metric Provider Priority property needs to be set to a value higher than Lowest, so we set it to Medium and regenerate our diagram.

In the runtime, you’ll find Validate and Metrics items in the Diagram menu. To test our audits and metrics, create a set of Topic elements with subtopics connecting them in a circle. At this point, our layout should be indication enough that cycles are a bad idea, as Figure 4-12 illustrates. Ideally, we’d add a link constraint to prevent cycles altogether. Nevertheless, run the Validate action and observe in the Problems view the warning of a cycle. Also notice the warning decorations added to each Topic; each violates the audit.

Figure 4-12 Mindmap audit violations

Image

Rename one of the Topics to a blank value and observe the live validation dialog, shown in Figure 4-13.

Invoke our diagram metrics and observe the Mindmap Diagram Metrics view, listing each Topic and providing the metric value in the NOS column, as seen in Figure 4-14. Those with values above the upper limit are displayed in red, and those below the lower limit are displayed in blue.

In our preferences, we now have a Model Validation category with options for live validation, in case the Practitioner chooses not to have a dialog pop up on each violation, as seen in Figure 4-15. Each constraint is also listed, with information on what it checks and the option to disable each, as seen in Figure 4-16.

Figure 4-13 Mindmap live validation

Image

Figure 4-14 Mindmap metrics

Image

Figure 4-15 Mindmap validation preferences

Image

Figure 4-16 Mindmap validation constraint preferences

Image

Note that audits and metrics defined using GMF are GMF-specific only when they’re written against the notation model. Otherwise, the generated code can be refactored for use in the domain model without a diagram. You will find the Validation Framework quite useful, particularly considering the extensibility provided with its declarative nature. You can add other audits and metrics by augmenting the generated plugin.xml file, or even from another plug-in. This is how our earlier audits and metrics are declared, not including the decorator and marker declarations:

image

image

You can find the generated code corresponding to these contributions in the classes MindmapMetricProvider and MindmapValidationProvider; both are in the org.eclipse.mindmap.diagram.providers package. They are not described in detail here, so take a look at the provided sample code and the documentation on the EMF Validation Framework for more information.

4.4 Developing a Requirements Diagram

We want a simple diagram that displays requirements so that we can visualize their relationships and dependencies. We first develop the diagram to be standalone, and then we integrate it as a tab in the generated EMF editor to illustrate the approach. Eventually, we want the requirements editor to be primarily form based.

4.4.1 Diagram Definition

Beginning with the Graphical Definition Model Wizard, we create a new requirements.gmfgraph model in our /diagrams folder of the org.eclipse.dsl.requirements project. In the wizard, be sure to select the Model class as the diagram element. Table 4-11 shows the completed model, indicating values that changed from their default.

Table 4-11 Requirements Figure Definition

Image

Image

Image

Note that the Resource Constraint property is set to NONE on both the Requirement and RequirementGroup nodes. This makes the node nonresizable. Another option to make an element nonresizable is to add org.eclipse.gef.editpolicies.NonResizableEditPolicy to the Primary Drag Policy Qualified Class Name property of the corresponding Gen Top Level Node property in the gmfgen model. Alternatively, you can use the NonResizableEditPolicyEx class from the GMF runtime.

A complication here is the label on the RequirementGroup, which, although nested within a nonresizable figure, causes the figure to grow by default as the text exceeds the width of the figure. To address this, the children Maximum Size, Minimum Size, and Preferred Size elements are added to the Rounded Rectangle to prevent resizing.

Notice that we have “hard-coded” the dependency link blue. Optionally, we can create a preference for this type of connection to allow the user to modify it, as you saw in the mindmap diagram Section 4.3.3, “Diagram Preferences.”

4.4.2 Tooling Definition

The tooling definition is straightforward, as always. We need two groups again: one for Nodes and the other for Links. Because of our numerous connection types, we need several Link tools, depending on their source and target types. Figure 4-17 shows the palette model. Here, we are more interested in simply displaying dependency relationships and are not so interested in allowing for the creation of elements on the diagram, so we could exclude a palette definition altogether.

Figure 4-17 Requirements tooling definition

Image

4.4.3 Mapping Definition

The structure of the requirements model differs from that of the mindmap model, in that children of RequirementGroups and Requirements are maintained in containment references of the elements, not in containment references of the root element. Thus, you can see how the mapping differs in this example. Figure 4-18 is our domain model to use as a reference through this discussion.

Figure 4-18 Requirements domain model

Image

The Canvas Mapping is straightforward, as Table 4-12 shows.

Table 4-12 Requirements Canvas Mapping

Image

For RequirementGroups, we have two mappings. The first represents groups that are contained in our canvas Model domain element; the second represents subgroups that are maintained as children of other groups.

The first mapping uses the groups reference of the Model class as the Containment Feature. The child Node Mapping is straightforward and listed in Table 4-13.

Table 4-13 RequirementGroup Node Mapping

Image

Notice from the table that we have a Constraint added to this node mapping, indicating that the parent reference must be null for this mapping to hold. We use the OCL expression parent.oclIsUndefined() to accomplish this. The second RequirementGroup mapping specifies that the parent must be a RequirementGroup using parent.oclIsTypeOf(requirements::RequirementGroup). If we had an eOpposite relationship with our Model class as we do between RequirementGroup and its children, we could have used parent.oclIsTypeOf(requirements::Model) in the first mapping.

For the first mapping, we specify a Tool, and in the second we rely on a Link to create a subgroup when drawn between two root groups. The Feature Label Mapping uses the id attribute, although with a fixed size of our RequirementGroup node, we expect the label to be truncated in the display. We’ll add ToolTips later, to allow diagram browsing to reveal the full name strings.

Jumping to the second RequirementGroup mapping, we see in Table 4-14 that no Containment Feature is specified for the node.

Table 4-14 Second RequirementGroup Node Mapping

Image

Note that no Tool is specified for this mapping. We’ve specified a node that uses the same figure as the previous RequirementGroup mapping but that will be created after a link is drawn between two groups. Note that this is not an example of the “phantom” node concept discussed in Section 11.3.3, “References, Containment, and Phantom Nodes.” In this case, all nodes added to the diagram canvas are legitimate because they’re being held in the Model’s groups containment reference. We’re just switching the containment feature from this to the children containment reference of RequirementGroup after a link is drawn between two groups.

Although we could achieve this change in containment for a node in other ways, this approach maximizes our use of generated code. We’ve defined constraints for each so that the generated code can uniquely specify each view mapping for the underlying semantic element. The Feature Label Mapping is the same as for the first RequirementGroup node mapping.

The Link Mapping for RequirementGroup specifies the children containment reference for subgroups, when drawn. The rest of the mapping is straightforward, as Table 4-15 shows.

Table 4-15 RequirementGroup Link Mapping

Image

Our Requirement node mapping does illustrate the “phantom” node concept. In this case, Requirement elements added to the diagram surface are not immediately placed in a valid containment reference; the Canvas is mapped to the Model class, which does not hold Requirements directly. A Requirement can be contained only in a RequirementGroup or as a child of another Requirement. So we specify the Top Node Reference with no Containment Feature, but we create two links that specify each of the two valid containments, as seen in Table 4-16.

Table 4-16 Requirement Node Mapping

Image

Image

As you can see, Node Mapping uses the Feature Seq Initializer element to create a new Version instance upon creation of a Requirement and set its major attribute to 1. This is a nice capability of GMF that would be beneficial in EMF as well. Table 4-16 gives the details of the Requirements Node Mapping.

The Requirements node has two Feature Label Mappings. The first is for an external label used to display the Requirement’s id attribute. The second is a Read Only label used to display the type of the Requirement in the center of its circle graphic, as Figure 4-19 shows. This works because we changed the Literal property of each Type enumeration to be a single letter: F in the case of FUNCTIONAL, N in the case of NONFUNCTIONAL. This is a simple solution, although it’s trivial to modify the generated code to return the first character or simply supply a character based on the selected enum.

Now we turn to our two Requirement link mappings. First is the mapping for Requirements that are maintained in the requirements feature of our RequirementGroup class, as shown by the Target Feature property setting. It uses the same Diagram Link we’ll use in the next mapping, but it has its own Tool, as seen in Table 4-17.

Table 4-17 Requirement Link Mappings

Image

The second mapping uses the children containment reference as the Target Feature and has its own Tool. Our final mapping is for Dependency

links. As you will recall from our graphical definition, these are blue dashed lines with open arrow head target decorations. We can use them to indicate dependency references between Requirements, as shown in Table 4-18.

Table 4-18 Requirements Dependency Link Mapping

Image

4.4.4 Generation

As before, we can right-click on our mapping model and select Create Generator Model to bring up the transformation dialog. The default requirements.gmfgen in the /diagrams folder is fine, so we proceed to the Select Mapping Model page, where our requirements.gmfmap model is already loaded. On the next page, we find that our requirements.genmodel is already selected and loaded as well. On the final page, we keep the defaults Use IMapMode and Utilize Enhanced Features of GMF Runtime, and then click Finish.

We now leave the default generation properties for the moment and generate our diagram plug-in using the Generate Diagram Code option from the file’s context menu. Launching the runtime workspace lets us create a new requirements diagram using the generated wizard found in the Examples category of the New (Ctrl+N) dialog. Figure 4-19 is a sample diagram.

You’ll notice right away that creating two RequirementGroup objects on the diagram, followed by linking these groups using the Child Group tool, requires pressing F5 to invoke a refresh to see the link. We need to modify the generated code to invoke a canonical update to avoid this, as we did in our mindmap with the override of handleNotificationEvent().

Figure 4-19 Requirements dependency diagram

Image

4.4.5 ToolTips

Because we have decided not to clutter our dependency view by displaying only the ID of each Requirement and RequirementGroup, we need to populate a ToolTip with the Requirement’s title. This provides a convenient way to browse the diagram with the mouse but not have to select each element and look in the Properties view to see its information. For now, we just display the title attribute value in a Label by modifying the createMainFigure() method of the RequirementEditPart class, as follows:

image

This works but suffers from the fact that if the title attribute is modified, the ToolTip does not reflect the change. We could override handleNotificationEvent() in our EditPart and update the ToolTip when changes are made, but a better solution is to leverage a custom EditPolicy. Furthermore, this is something we’ll potentially need for our RequirementsGroup because it is also a fixed-size shape that requires selection and the Properties view currently to get the full text. Instead of continuing to modify the generated code, this seems like a good opportunity to add a decorator model to our requirements.gmfgen model to specify ToolTips and their displayed attributes for selected elements. We begin by creating a simple tooltip.ecore model in the /diagrams folder of our requirements project, with just a root Model element that contains a collection of ToolTip elements, which, in turn, contains a number of DisplayElements. The important aspect of the model is the reference from the ToolTip to the GMF generation model’s CustomBehaviour class, as shown in Figure 4-20 using a diagram shortcut.

Figure 4-20 ToolTip model

Image

We plan to implement a custom EditPolicy for our ToolTip, which is the standard GEF approach for adding behavior to an EditPart. It might seem like overkill when you see the actual implementation, but this gives us an opportunity to illustrate this extension approach.

The GMF generator model enables us to define Custom Behaviour elements as children of Gen Top Level Node elements. We need to add a reference from our Tooltip class to this element in the GMF generator model. Using the Load Resource menu followed by the convenient Browse Registered Packages button brings up the dialog shown in Figure 4-21. It takes a few seconds to populate, but when it does, we select our GMF GenModel from the list. Be sure to select Runtime Version and not Development Time Version, and then accept the corresponding warning that models referenced in this manner will not appear as a root in the editor. Selecting Runtime Version means that references to this loaded model will use the registered package Namespace URI instead of a platform:/ URI, as is the case when selecting Development Time Version.

Figure 4-21 Package Selection dialog

Image

We now create an editpolicy reference from our Tooltip class to the CustomBehaviour class in the loaded GMF GenModel. To reference the text we need to display in our ToolTip, we add a reference to the Ecore EAttribute element. Similar to our earlier procedure, we first use the Load Resource menu item to add the http://www.eclipse.org/emf/2002/Ecore model to our resource set using the Runtime Version, and we create a new reference to our ToolTip class named textAttribute of type EAttribute.

In our requirements.gmfgen model, navigate to the Gen Top Level Node RequirementEditPart element and add a new child Custom Behaviour element. It’s a simple element, with just Key and Edit Policy Qualified Class Name properties, which we set to “TooltipPolicy” (the quotation marks are required) and org.eclipse.requirements.diagram.edit.policies.
RequirementsTooltipEditPolicy
, respectively. The parameter used to install an EditPolicy is a String, which typically comes from constants defined in either the GMF runtime’s EditPolicyRoles interface or GEF’s EditPolicy interface. Look at the policy roles defined here before you create your own. If you reuse a defined constant, you don’t need to wrap it in quotes.

Next, we need to create a Dynamic Instance of our ToolTip model for use in generating our custom EditPolicy. This is much more convenient than the alternative, which is to create a tooltip.gen model and generate model code, followed by deploying that model into the environment. From the Ecore editor, we right-click our Tooltip element and select Create Dynamic Instance and select our /diagrams folder for the new Tooltip.xmi model. In the Sample Reflective Ecore Model Editor, use Load Resource to load our requirements.genmodel from the workspace. Now we can select the Custom Behaviour element that we added previously for our Editpolicy property. This is where the option of using the Runtime Version in our loading of the GMF GenModel earlier becomes important, for if we left the reference as platform:/plugin..., we would not have seen our Custom Behaviour element in the list.

Finally, set the textAttribute property of our Tooltip instance to the title:EString attribute of our Requirements class, which was loaded into the resource set when we loaded the requirements.gmfgen model.

After we add the Custom Behaviour element to the generation model, the generated code references the ToolTip class. The GMF generator knows nothing of our custom template, and there’s no way currently to add new template definitions to the execution environment. We need to create our own workflow and run a second-generation step to produce the referenced ToolTip EditPolicy class. Section 14.1.1, “Workflow Engine,” covers workflows, but for now, just use FileNewOtherModel TransformationWorkflow Definition to create a tooltip.mwe file in the /workflows folder. Next you can see the workflow used to invoke our template following the normal GMF diagram generation; it includes a number of model references. As such, it’s necessary to add the following plug-ins as dependencies of our project in the MANIFEST.MF file: org.eclipse.gmf.codegen, org.eclipse.gmf.runtime.notation, and org.eclipse.gmf.validate. Curiously, you also need to add org.eclipse.core.runtime, org.eclipse.jdt.core, and org.eclipse.jface.text.

image

We need a template named TooltipEditPolicy.xpt that we can place in a /templates-diagram folder of our org.eclipse.dsl.requirements project. This folder needs to be added as a source path in the project; as does the /diagrams folder, we’ve placed our tooltip.ecore model and corresponding dynamic instance there. Following is the content of the Xpand template file, which could use some improvement. Chapters 7 and 14 cover Xpand, so we don’t get into the details here.

image

image

The template makes use of an Xtend utility named Utils.ext, whose contents are shown here for those who are interested. Again, later chapters cover the details of Xpand, Xtend, and Workflow.

image

For completeness, this is the content of the Tooltip.xmi file used to complement our GMF generation with a custom EditPolicy that presents Requirement title and author attributes in a ToolTip on mouseover events:

image

We can execute the workflow by right-clicking the tooltip.mwe file and selecting Run AsMWE Workflow. After execution, our new TooltipEditPolicy is generated into our requirements diagram project. Don’t forget to regenerate the diagram code from the requirements.gmfgen model as well; the code required to install our custom editpolicy on the RequirementEditPart needs to be generated. If we launch the diagram, we can test the result, as Figure 4-22 shows.

Figure 4-22 Requirement ToolTip

Image

4.4.6 Integrating EMF and GMF Editors

For our requirements diagram, we want it to be a page within a multipage editor rather than a standalone diagram. The reason is that it’s more of a dependency visualization diagram than a requirements editing environment, although it does have editing capabilities. An Eclipse Corner article [47] provides much of the detail on how to accomplish integrating EMF and GMF editors this way, so we imitate that approach here.

Sharing File Extension

To begin, we need to open our requirements.gmfgen model and make some changes, as shown in Figure 4-23. The Diagram File Extension property should match the Domain File Extension—in this case, requirements. Also, we need to change the Same File For Domain And Model property to true.

Figure 4-23 Requirements GMF generator model

Image

At this point, regenerate the diagram code and launch the runtime workbench. Create a new Requirements Diagram using the GMF-generated wizard and populate it with some data. Right-click the .requirements file you created and select Open WithRequirements Model Editor, which is the EMF-generated editor. You’ll find that the model has two roots: one for the domain model and the other for the diagram notation model. Note that if you try to create a new Requirements model using the GMF-generated wizard at this point, you’ll get an error stating “Resource contains no diagram.” Also, if you have an existing .requirements model in your workspace and attempt to initialize a diagram for it using the context menu, it will work fine. If you subsequently reopen this .requirements model in the EMF-generated wizard, you’ll notice that the diagram notation model has been added as a second model root.

Furthermore, if you open the two editors simultaneously, you will notice the following behavior. Changes made in the EMF editor do not appear in the diagram until the EMF editor has been saved. As soon as you save the EMF editor, you’ll notice a dirty marker appear on the diagram editor. Newly added elements are found in the upper left and require diagram layout. Likewise, the EMF editor does not see changes made to the diagram until the diagram is saved. Switching to the EMF editor results in a refresh that collapses the tree, though no dirty marker appears on this editor. The two editors are at least aware of changes made to the files they have open, but it’s not quite good enough. Let’s return to our development workspace and continue.

Sharing an Editing Domain

Although both editors use an EditingDomain, they use their own; the EMF editor uses an AdapterFactoryEditingDomain, and the GMF editor uses a TransactionalEditingDomain. We need them to share a single TransactionEditingDomain, so we must modify the generated EMF editor code. To use this class, we need to add the org.eclipse.emf.transaction plug-in to our list of Require-Bundle dependencies in the MANIFEST.MF file. Now open the org.eclipse.requirements.presentation.Require-mentsEditor class found in the generated org.eclipse.requirements.model.editor plug-in. Mark the initializeEditingDomain() method as @generated NOT, and replace the code that creates a new BasicCommandStack with the creation of a new TransactionalEditingDomain; then use its getCommandStack() method to add the listener. At the bottom of the method, cast the TransactionalEditingDomain to the expected AdapterFactoryEditingDomain, making the method appear as follows:

image

Open your requirements.gmfgen model and locate the Editing Domain ID property in the Editor category of the Gen Diagram ModelEditPart element part. Set the value of this property to the same ID we previously set for the TransactionalEditingDomain, as seen in Figure 4-24.

Figure 4-24 Requirements editing domain

Image

With our editors sharing a common editing domain, now we turn to each of our pages in the multipage editor because they need a reference to this shared domain. Fortunately, GMF comes with a FileEditorInputProxy class that we can use to initialize each of the pages. First, we need to add a dependency from our EMF editor plug-in to our org.eclipse.requirements.diagram plug-in and re-export all the org.eclipse.gmf.runtime.* plug-ins from the diagram editor manifest. After this, navigate to the init() method of the RequirementsEditor class. Mark the method with @generated NOT and modify accordingly (changes in bold):

image

With our diagram becoming just another page in a multipage editor, we need to modify its generated code a bit to take into account the passed FileEditorInputProxy. Open the org.eclipse.requirements.diagram.part.RequirementsDocumentProvider class and replace all uses of org.eclipse.ui.part.FileEditorInput with org.eclipse.ui.IFileEditorInput, with the exception of the method handleElementMoved(). Don’t forget to mark each section with @generated NOT.

Next, we need to modify the createEmptyDocument() method so that it uses the passed EditingDomain instead of creating its own. Actually, we have the original method delegate to a new method that takes an input parameter and modify the createDocument() method to pass its parameter as follows (changes in bold):

image

Refactoring the Editor

Back to our EMF-generated RequirementsEditor, we see that each page is created as an anonymous subclass of ViewerPane. This causes problems when trying to integrate our diagram into a page, so we can create an abstract RequirementsEditorPart class to use as a superclass for converting each page into its own EditorPart. Create the new class in the org.eclipse.requirements.presentation package that extends EditorPart and implements IMenuListener and IEditingDomainProvider as follows:

image

image

We actually don’t want to use all of the EMF-generated pages in our multi-page editor. We’ll use just a selection tree and a diagram, so we can remove the rest. We create a new SelectionTreeEditorPart that extends our RequirementsEditorPart and migrate code from its original anonymous subclass of ViewerPane from the RequirementsEditor class, as shown here:

image

We can refactor the RequirementsEditor.createPages() method now to use our SelectionTreeEditorPart class. As mentioned, we eliminate all but one of the standard EMF-generated pages, including the parent tree view, which means that we can eliminate the inner ReverseAdapterFactoryContentProvider class altogether. Following is our createPages() method, which initializes the selectionTreeEditorPart class attribute that we’ll add to the class. We’ll return to this method to add our diagram page later.

image

Selection Handling

Before we clean up our RequirementsEditor class, we need to fix the selection handling we disrupted by splitting up the editor. MultiPageEditorPart already provides a mechanism to handle selection changes, so we can refactor the code to use it. We add a MultiPageSelectionProvider selectionProvider attribute to the class and initialize it in the constructor. We then set this instance as the sitewide provider in the init() method, thereby eliminating the need for the editor to implement ISelectionProvider. Changes are in bold.

image

The selectionChanged() method calls upon a new updateSelectionActions() method that we add to our RequirementsDiagramEditor, which appears here:

public void updateSelectionActions() {
  updateActions(getSelectionActions());
}

In the handleActivate() method, we need to leverage the selectionProvider as well (changes in bold):

image

Our setCurrentViewer() method becomes much simpler because it no longer needs to deal with selection handling.

image

Finally, we need to refactor our handleContentOutlineSelection() method.

image

Our editor no longer is responsible for being an ISelectionProvider, so we can eliminate this interface from the implements list and all associated code. Attributes selectionChangedListener, selectionChangedListeners, and editorSelection can be removed, along with their associated methods addSelectionChangedListener(), removeSelectionChangedListeners(), getSelection(), and setSelection(). We no longer need the currentViewerPane or the viewers, so we can remove these (except currentViewer) as well. We also can remove the setFocus() and isDirty() methods.

Finally, we can add the diagram to a page in our editor. Back in createPages(), enter the following code and corresponding RequirementsDiagramEditor diagramEditor class attribute:

image

We need to revisit our handleContentOutlineSelection() method to take into account the diagram page because we want to map the selection to the proper EditPart on the diagram (changes in bold):

image

If we launch the runtime workbench and open one of our existing .requirements models, we will see that our editor now has two pages: one the familiar Selection page, the other our new Diagram page. Although it’s working, we need to fix a few more items, including the Properties view, which currently does not respond to diagram selections. Also, you’ll notice that the diagram toolbar is missing and that the Outline view has no diagram overview.

Properties View

The explanation for the Properties view not working is obvious. GMF editors use the tabbed properties by default, but EMF uses the “classic” view. We can update the RequirementsEditor to implement ITabbedPropertySheetPageContributor, add method getContributorId(), and update getPropertySheetPage(). Note that we need to change the type of propertySheetPage to PropertiesBrowserPage.

image

This fixes our diagram page but breaks our tree selection page. The reason is that the contribution to the *.tabbed.propertySections extension-point made in the diagram editor plug-in does not include the raw EMF model types in our model. We need to add them, as shown here:

image

While we’re here, let’s remove the org.eclipse.ui.editors contribution from our diagram plug-in manifest because we no longer need it.

Menus and Toolbar

To address the issues with menus and toolbars, we can add two classes provided in the article to our org.eclipse.requirements.presentation package: RequirementsMultiPageActionBarContributor and SubActionBarsExt. These are slightly refactored from the originals and are not covered here. Basically, the first class is a composite ActionBarContributor that handles switching between pages where each has its own contributor. The second class is a utility class used by the first. To use these classes, we need to modify two methods—first, the getActionBarContributor() in Require-mentsEditor:

image

In RequirementsEditorPart, we need to modify menuAboutToShow()

as well:

image

The new contributor needs to be registered in our editor contribution, replacing the original:

image

Our edit menu actions are still in need of repair. Again, we need to “upgrade” the EMF-generated editor by having RequirementsEditor implement IDiagramWorkbenchPart, with each of its methods delegating to our diagramEditor:

image

Our diagram plug-in manifest contains contributions to globalActionHandlerProviders, each using the ID of the diagram editor. We need to either modify the IDs to be that of our EMF editor (now multipage), or copy this contribution to the other editor manifest, change the IDs, and make the priorities higher than the diagram editor. We opt for the second approach here, pasting the entire globalActionHandlerProviders section into the org.ecilpse.requiremements.model.editor plugin.xml file, replacing the three Priorities with Low and changing each of the ViewIds to org.eclipse.requirements.presentation.
RequirementsEditorID
.

Creation Wizard

Recall the “Resource contains no diagram” error we received when attempting to create a new Requirements model using the EMF-generated wizard. The EMF-generated wizard knows nothing about creating the diagram, which is an instance of the GMF notation model. We need to modify the performFinish() method to create and initialize a diagram when the domain model is created (changes in bold).

image

We’ll use this Wizard exclusively to create requirements models, so we can remove the newWizards contribution in our diagram plug-in manifest.

Navigator and Outline

The Project Explorer view in the Resource perspective enables us to drill down into our .requirements file and navigate its contents. However, if we attempt to do this, we’ll get ClassCastExceptions in the error log because we have a diagram contents contribution to the navigatorContent extension-point that doesn’t know how to handle domain model elements. To fix this issue, we simply set the activeByDefault property of this contribution to false, as shown in Figure 4-25. More is involved in making the navigator truly useful, but this at least avoids the exceptions.

Figure 4-25 Requirements navigator extension

Image

Our selection trees in the editor and the Outline view both show diagram content. Later we’ll want to fix the Outline view so that it again gives us the “bird’s-eye” view of the diagram when the diagram page is selected, but for now we just filter diagram content from our tree viewers. The process is the same for both, so we only show the changes made to SelectionTreeEditorPart.createPartControl() here. The same change needs to be made to RequirementsEditor.getContentOutlinePage(). As shown here, it’s simply a matter of adding a ViewerFilter that excludes instances of Diagram from the view (changes in bold).

image

At this point, we can run our editor and test its functionality. We still have some bugs to work out, but it’s largely functional at this point.

Properties Revisited

The default generated properties from both EMF and GMF are simple tables, with the exception of diagram element properties that use form-based property sheets. The default is fine for certain property types, but it’s painful to deal with long text strings such as a requirement’s description property. Even the EMF generator model’s Property Multiline option is painful because you need to first open a dialog from the Properties view. In this section, we generate a custom property sheet tab that we can use to provide a large text area for the description property.

To begin, open the requirements.gmfgen model and navigate to the Property Sheet element. Create a new Custom Property Tab element and populate it according to Table 4-19. Note that we’re interested in only the Requirement class, so we enter its domain model class and corresponding diagram EditPart class.

Table 4-19 Requirements Custom Property Tab

Image

Image

When we regenerate our diagram, we find the following additions to the plugin.xml file and the default generated property section class. Note that if you marked the propertySections element as generated=“false” during the steps to combine editors, you don’t see the new property section. To regenerate in this case, set the value to true after backing up the changes and merge manually afterward.

image

The generated class extends the runtime’s AdvancedPropertySection class. This provides the same table style of property view we’re trying to replace, so we can delete the class content and have it extend the provided AbstractBasicTextPropertySection class, as shown here. This class provides a simple text field with code that sets up a forms-based property sheet, just as we wanted. Some changes we’ve made include the use of a text area and not a single line text field. Also, we have overridden the unwrap() method to identify our Requirements class or edit part properly, ensuring that the sheet will work when selections are made in both the diagram and tree view.

image

image

Figure 4-26 shows the result. Although we still have some work to do, this gets us started converting our table view to forms view properties. If you’re interested in developing a model to define the property sheets and using custom templates to generate these form-based sheets, take a look at the GMF graphical definition model editor. This editor provides WYSIWYG editing of figures when developing diagrams, but it is still in the “experimental” SDK. It also supports the definition and generation of forms-based property sheets and editors through the use of a collection of models found in the org.eclipse.gmf.formtk plug-in.

Figure 4-26 Requirement description Properties tab

Image

One thing about the Properties view that we notice in our generated GMF diagrams is that the Properties view cannot handle the selection of multiple diagram elements. For example, try selecting multiple topics in our Mindmap diagram or selecting multiple requirements in our Requirement diagram. The Core tab of the Properties view goes blank. To resolve this, open the RequirementsPropertySection class in our requirements diagram. It’s located in the org.eclipse.requirements.diagram.sheet package. To enable multiselection, we need to have the getPropertySource() method return an instance of EMFCompositePropertySource instead of the generated PropertySource default. This is the method showing the change:

image

This displays the properties of selected items for edit in the Properties view, but only if they are of the same type. However, we want only properties that make sense to change on multiple elements at a time to be editable. It doesn’t make sense to change all the requirement IDs to the same value, for example. We leave this refinement as a future enhancement and move on to our next diagram.

4.5 Developing the Scenario Diagram

As mentioned already, we want to leverage the BPMN notational elements for our Scenario diagram. Unfortunately, no BPMN2 diagramming component exists within MDT, and the BPMN project within the SOA Tools project uses an older version of GMF and does not generate its figures to a standalone plug-in. Fortunately, this gives us an opportunity to show how this is done as we develop this diagram.

4.5.1 Graphical Definition

The BPMN specification defines many notational elements. We start with those to be used in our scenario diagram, but the idea is to create a figures plug-in that can be reused as a reusable library for any BPMN-based diagram. To begin, we create a new org.eclipse.dsl.bpmn project and, within it, a new bpmn.gmfgraph model in the /diagrams folder. In this case, we’re interested in only the graphical definition, which we can use to generate a standalone plug-in and mirrored.gmfgraph model that we’ll be referencing in our scenario diagram definition.

Each of the elements defined in our graphical definition is covered in a later subsection. Although we could define them all and then do the tooling and mapping, it’s typically better to work iteratively. So although in each section it appears as though it was all done in a waterfall manner, the figures, their tooling, and their mappings actually were all done one or two at a time with many gmfmap→ gmfgen→ code iterations in between.

Also, notice the use of Figure Ref elements in the graphical definition. BPMN has several elements that contain common internal notation, so this reuse capability prevents copying/pasting/updating figures. For example, the envelope image in Figure 4-27 can appear within three different Event types.

Figure 4-27 Figures with inner elements

Image

Task and Subprocess

We begin by creating a Task figure, which will be similar to our mindmap Topic figure, including the modifications we’ll do to fix the stack layout and text wrapping covered in Section 4.3.3, “Topic Figure Layout.” Figure 4-28 shows these elements, along with their figure and node settings, beginning with a Task. Table 4-28 shows the detail of the Task figure definition.

Figure 4-28 Scenario task figures

Image

Table 4-20 BPMN Task Figure Definition

Image

We don’t want Task items to be sized below a defined minimum, which is also the preferred size. As such, we don’t need to set a Default Size Facet on the node element. As mentioned, Tasks can have border items, as shown in Figure 4-28. The Affixed Parent Size property used to enable this capability is set on the border item itself, as described in Section 4.5.5, “Events.”

A Subprocess is similar to a Task element, with the addition of a small box with a plus sign located at the bottom center. Additional decorators are defined in the specification to indicate looping, parallelism, and so on, but these are not covered here. Table 4-21 defines the Subprocess figure and node.

Table 4-21 BPMN Subprocess Figure Definition

Image

Image

Image

We need to point out a few things in this graphical definition. First, a Figure Ref element points to the ExpandBox figure at the root of the Figure Gallery. The reason for this reference is that we will likely create additional subprocess figure elements to include decorations for additional types, thereby allowing reuse of this figure. Note that the plus symbol (+) itself for the box is an ordinary Label element, not a polyline. Using text elements such as this is not always a good idea because diagram scaling might not work as desired. Its use here is illustrative.

Also note the use of layout elements to achieve a text area on top with the ExpandBox figure centered at the bottom of the Subprocess node. A combination of Grid, Border, and Stack layouts is used.

Gateways

The Gateway item is a simple diamond but is decorated by an internal figure depending on the type: exclusive, inclusive, or parallel. The exclusive gateway has no decoration, and the specification has variants we don’t implement here. The inclusive gateway has a heavy-lined inner circle figure, and the parallel gateway has a “plus” sign at its center, as seen in Figure 4-29. Table 4-22 defines each figure, as well as an image of the exclusive, inclusive, and parallel gateway figures (from left to right).

Figure 4-29 BPMN gateway figure definitions

Image

Table 4-22 BPMN Gateway Figure Definitions

Image

Image

* It should be possible to use a Figure Ref element here to point to a single Diamond figure definition, as we use elsewhere. At the time of this writing, the generated code is incomplete.

Note that the figures are fixed in size, although it would be possible to define each as scalable figures. Also note that each will be fully generated, with no template or code modification.

Events

As with Gateways, many flavors of Event notation elements exist, as shown in Figure 4-30. The basic shape is a circle, with the outline determining its type. A normal outline (single line) represents a Start Event, and a thick border outline represents an End Event. A double outline represents an Intermediate Event. Within the circle, numerous “triggers” are defined in the spec, although only the definition of a message trigger (envelope) is provided here. Following are examples of Start, Intermediate, and End Event elements and their corresponding Message trigger alternatives. Table 4-23 gives figure and node definitions.

Figure 4-30 BPMN events

Image

Table 4-23 BPMN Event Figure Definitions

Image

Image

Image

Image

* Note that the DoubleCircle definition is identical to the BasicCircle. We modify the generated code in Section 4.5.5, “Intermediate Event Outline,” to draw the second outline.

These figures are fairly straightforward, with the most complex part being the definition of the Envelope. Note that in addition to reuse of the Envelope using Figure Ref elements, figure reuse takes place in Node definitions (for example, as I used in the DoubleCircle node for both the standalone and border item Intermediate Event).

Connections

BPMN has several connection types, including Association, Message Flow, and Sequence flow, which are covered here. These are straightforward definitions, with the exception of the source decoration on the Message Flow—we need to code it by hand and reference it as a Custom Figure. Figure 4-31 shows images of each connection we define in Table 4-24: Normal Sequence Flow, Default Normal Sequence Flow, Association, Directed Association, and Message Flow (from top to bottom).

Figure 4-31 BPMN connection types

Image

Table 4-24 BPMN Connection Figure Definitions

Image

Image

Image

* We specify the Implementation Bundle property here as we reference a Custom Figure for our Message Flow source decorator. This allows the generated code to include the proper plug-in dependency while we develop the diagram. When the standalone figures plug-in is generated, this value automatically is entered into the generated mirrored.gmfgraph model, and we separate our custom code into its own project source path.

Note the Diagram Label and associated Label figure. This label is generic for all external labeling needs, such as that used by the Normal Flow connections in the mapping model. This represents another form of reuse because this single external label is used for connections and our Data Object node, as shown in the next section.

Data Object

A Data Object in BPMN refers to an artifact that can be associated with a flow object using an Association link or can be passed with a sequence flow. The notation is a simple document and uses the traditional dog-ear corner. Figure 4-32 shows an example of the Data Object being used in both directed and nondirected associations; Table 4-25 gives its figure and node definition.

Figure 4-32 BPMN data object

Image

Table 4-25 BPMN Data Object Figure Definition

Image

Aside from the list of Template Points, this figure definition is nothing special. Note the use of Default Size Facet again, as well as NONE for the Resize Constraint. The default size of a node is 40×40, which would leave our document within a larger rectangle when selected. Not only does this look odd, but it also prevents connections from reaching their true target.

4.5.2 Tooling Definition

We have several types of certain tools, so here we exploit the use of stacks in our scenario diagram palette definition. We also show in our mapping model that we can reuse a tool to create more than one type of node, even without a stack of tools or a pop-up menu. In this case, the Events that are placed either on the diagram or on the border of a Task use the same tool; the target of the mouse determines the proper context for the tool, to determine the correct node to create.

Figure 4-33 shows our scenario.gmftool model and its generated palette. A palette with one of its stacked tools expanded is also shown. Creating the model is straightforward; the only noteworthy step is to set the Stack property to true for nested Tool Group elements. Note that the palette shows nondefault icons, which are added in Chapter 8, “DSL Packaging and Deployment.”

Figure 4-33 Scenario palette definition

Image

4.5.3 Mapping Definition

The mapping definition for the scenario diagram is fairly straightforward because the main elements containment reference of the Process class will be used to store all elements other than border events, which are stored in the events containment reference of the Task class. Each of these sections follows that of the graphical definition section and discusses the mapping of each major diagram element, leaving the particulars to be explored in the supplied sample code. Table 4-26 shows the mappings with details for the Canvas Mapping.

Table 4-26 Scenario Canvas Mapping

Image

Task and Subprocess

Task mapping is the most complicated because of the border items of a Task, although it is straightforward, given the mappings we’ve accomplished so far in the book. Table 4-27 shows the mapping structure.

Table 4-27 Scenario Task Mapping

Image

Image

Two Child Reference elements represent the two Event border items: BorderedIntermediateEvent and BorderedMessageIntermediateEvent. These elements are stored in the Task’s events: Event Containment Feature. For their Node Mapping, they use their corresponding Node definition but the same Creation Tool we use for these events when placed on the diagram surface (Intermediate and Message Intermediate).

To distinguish border Events, as they represent instances of the same Event class from our domain model, we use Constraint and Feature Seq Initializer elements. As shown in the mapping, both the eventType and triggerType attributes are specified in the constraint and feature initialization.

The CollapsedSubprocess node is mapped in much the same manner, yet it has no Child Reference elements. Section 4.5.5, “Subprocess Partition,” covers how to use the Related Diagrams property of the Node Mapping, enabling us to double-click on a Process element and open it in a new diagram.

Gateways

All Gateway elements map in a similar manner because they all represent a Gateway domain element initialized to different GatewayType enumeration literals. Table 4-28 gives the mapping, where, again, the Top Level Node Containment Feature is set to our Process elements:Element reference.

Table 4-28 Scenario Gateway Mappings

Image

Events

Again, we can map each of our Event nodes to their corresponding Event domain element and add a Constraint and Feature Seq Initializer to set the eventType and triggerType attributes accordingly. All of the six Event mappings are done in the same manner, as seen in Table 4-29.

Table 4-29 Scenario Event Mapping

Image

Connections

We must define five Link Mapping elements, with all but the Message Flow mapping following the pattern given. For Message Flow, only one type exists, so there is no need to add the child Constraint and Feature Seq Initializer elements as with the rest. Each link maps to the Connection class in the domain element, with our usual Containment Feature of the Process elements:Element reference. A Source Feature and Target Feature are specified, mapping to the source:Element and target:Element references, respectively. The appropriate isDirected constraint and initializer are set for the Association mappings, while the isDefault property is checked or initialized for the Sequence Flow mappings. Each Link Mapping has an external Feature Label Mapping for the name attribute, as seen in Table 4-30.

Table 4-30 Scenario Link Mappings

Image

Data Object

The Data Object mapping is the most basic, with just a Node Mapping for the DataObject domain element to its corresponding DataObject node and Creation Tool, along with a Feature Label Mapping for its name:EString attribute.

4.5.4 Generation

As usual, we invoke the transformation from mapping to generator model using the context menu Create Generator Model on our scenario.gmfmap model. In the generator model, we change the Diagram File Extension property to scenario, and we set the Same File For Diagram And Model property to true, as seen in Figure 4-34.

Figure 4-34 Scenario GMF generator model

Image

We next generate our scenario diagram plug-in and move on to making some of the necessary code changes—or you can run the diagram now to see how it looks.

Border Item Adjustment

Our border item Event nodes are offset by default so that the edge of the node meets the edge of the parent. For our Event nodes, we want them to straddle the border, so we must modify the addFixedChild() method of the parent TaskEditPart class to set the offset to half the diameter of the Event circle figure. The modified method follows, showing the general EventXEditPart modification, where X is replaced by the number of each side-affixed event. A better solution would be to use childEditPart.getSize().width/2 to calculate the offset. Changes appear in bold.

image

Figure 4-35 shows the result of the change, showing the before and after versions.

Figure 4-35 Task border item

Image

Intermediate Event Outline

Our graphical definition model has no “double line” option, so we need to write some custom code to create a double outline for our intermediate event. We can do this in several ways, including nesting figures. It seems easiest to simply override the outlineShape() method in our generated Ellipse figure. Following is the modification made to accomplish this, though it won’t work if we have a line width other than 1. Fortunately, we know that we won’t, because otherwise we’d take the time to put the additional logic in the templates and provide a decorator model for our graphical definition model. The following code is found in the generated Event2EditPart class. After generating the figures plug-in in Section 4.5.5, “Generating the Figures Plug-In,” you can find the code to modify in org.eclipse.bpmn.figures.DoubleCircle and associated DoubleCircleWithEnvelope.

image

Figure 4-36 shows an example of our Scenario diagram to this point.

Figure 4-36 Scenario diagram

Image

4.5.5 Generating the Figures Plug-In

We must generate a standalone figures plug-in for use in our diagram. As mentioned earlier, this is the preferred way to develop GMF diagrams, but it comes at the expense of a slightly complicated workflow. Begin by right-clicking on the bpmn.gmfgraph model and select Generate Figures Plug-In. Specify the name org.eclipse.bpmn.figures for the plug-in name and select the Use IMapMode and Utilize Enhanced Features of GMF Runtime options before clicking Finish, as seen in Figure 4-37.

Figure 4-37 Figure Gallery Generator dialog

Image

Upon finishing, you will observe a new plug-in project with generated figures code and a mirrored.gmfgraph model. If you compare this model to our original, you’ll note that it contains identical canvas elements (nodes, connections, diagram labels), but the figures are all declared as custom with references to their generated classes.

From now on, when working with figures, you need to regenerate the plug-in and mirrored.gmfgraph model. The complication here is that the model is not in the same resource set as your gmfmap model, and changes are not reflected in referenced elements. This means it’s a good practice to design your figures up front; if you do make a change, be sure to return to your mapping model after regeneration and update any references that might have been impacted. The mapping model references only canvas elements, not elements within the Figure Gallery, so it is cause for concern only when changing nodes, compartments, links, and diagram labels.

At this point, we’re ready to change our scenario.gmfmap model to use the mirrored.gmfgraph now located in our org.eclipse.bpmn.figures project. Unfortunately, GMF does not provide a Migrate to Standalone Figures utility GMF, so we’re left to make the changes manually in a text editor. In our case, it’s a straightforward search and replace of all bpmn.gmfgraph occurrences with platform:/resource/org.eclipse.bpmn.figures/models/
mirrored.gmfgraph
; we can use Validate to ensure that we didn’t make a mistake. Note that we use the platform:/resource/... URI type and not the usual relative path. If we were referencing a deployed plug-in in our environment or target, we’d use platform:/plugin/... instead, which should make updating this mapping model easy if we deploy these figures.

We have to do a couple more things before we regenerate our diagram. Recall that we previously had figures generated during the gmfmap→gmfgen transformation, so our figures are currently located in our EditParts as inner classes. First, we want to relocate our custom CircleDecoration class into our new figures plug-in, but in a new src-custom source folder. This makes our regeneration easier because we don’t have to worry about deleting this custom class. Also, this class will be available to other diagrams that want to use the decoration for other links. In fact, we can go back to our Mindmap diagram and reference this decoration. After we copy the class into the /src-custom/org/eclipse/bpmn/figures folder, our generated figures code will compile without error.

The second thing we do is move the bpmn.gmfgraph model to our generated figures plug-in. This keeps the original source model near its mirror and makes the source figures available to those who are creating diagrams and want to extend them instead of using only the mirror’s custom figure elements. We can later modify the graphical definition and regenerate the figures code into this same project.

Now that we’ve separated figures from our model, we can re-create our generator model and regenerate the scenario diagram. Notice that the updated scenario.gmfgen model no longer contains serialized figures, but references our org.eclipse.bpmn.figures plug-in, which has been added to our diagram’s dependency list. At this point, we need to reimplement the changes we made to our intermediate event figures (DoubleCircle and DoubleCircleWithEnvelope) in Section 4.5.5, “Intermediate Event Outline.” And we need to modify our NamedRoundedRectangle and CollapsedNamedRoundedRectangle figures to adjust the stack layout and enable text wrapping of our labels, as described in Section 4.3.3, “Topic Figure Layout.” If you choose to delete the diagram plug-in entirely, you also need to make the changes to the TopicEditPart for overlapping events in Section 4.5.5, “Graphical Definition.”

4.5.6 Diagram Partitioning

This section covers the two main use cases for diagram partitioning, which the Related Diagrams property of a Node Mapping supports. First, we simply allow subprocess elements on our scenario diagram to open a new diagram editor page where the subprocess will be modeled. Second, we add the capability for a Requirement element on our requirements dependency diagram to reference and open a scenario diagram.

Subprocess Partition

It’s as simple as setting the Related Diagrams property in our scenario.gmfmap model for the Subprocess Node Mapping to its Canvas Mapping for the subprocess partition to work. In the scenario.genmodel, this results in an Open Diagram Behaviour element being added to our Gen Top Level Node for the subprocess node, as shown in Figure 4-38.

These default generated values give us the desired behavior of doubleclicking on a subprocess node to open an new diagram instance in the editor. After doing so, open the diagram file in a text editor and notice that, for each partition, a diagram element exists within the file.

Figure 4-38 Scenario open diagram edit policy

Image

Looking at our generated policy class, you can see that it uses the HintedDiagramLinkStyle from the notation model. If you look at the generated Process2ViewFactory, you can see how this style is added to our Subprocess view element.

image

When we define the next partition, it will be to another diagram type, where the code will include a call to setHint() so that the open diagram action knows the type of diagram to open.

Requirement to Scenario Partition

It’s slightly more complicated to have a related diagram be of a type other than the one specifying the partition, but not a lot more. We want to have a scenario diagram associated with a requirement and opened from the requirement dependency diagram. To do this, we need to associate a Process element in our scenario model from our Requirement element. This is necessary for two reasons: The node that has the Related Diagrams property set must be of the same type as that representing the canvas of the target diagram, and, as such, there must be a reference into which created domain elements of that type can be added when elements are added to the diagram.

Opening our requirements.ecore model, we use Load Resource to load our scenario.ecore model into the resource set. To the Requirement class, right-click and add a new EReference named scenario of type Process. Set the Containment property to true. Reload the requirements.genmodel and add a reference to the scenario.genmodel before clicking Finish. Right-click on the requirements package root in the genmodel and regenerate the model, edit, and editor code. If you’re interested, launch and test the requirements editor, adding a new Process to a Requirement instance. If you do, you’ll notice that no properties exist for the new Process element, which should remind you to add the org.eclipse.scenario.Process input type to the diagram plug-ins propertySections contribution. Otherwise, we move on to modify our requirements diagram definition to allow new scenario diagram partitions.

Beginning with the requirements.gmfgraph model, we now create a new BasicDiamond figure in our gallery. This is much the same as our BasicDiamond figure in the bpmn.gmfgraph model, although it’s smaller because we intend to add it as a side-affixed node to our Requirements circle. Table 4-31 lists the additions.

Table 4-31 Diamond Figure Definition

Image

Image

In our requirements.gmftool model, we add a new creation tool in the Nodes group for the Scenario element by copying another tool and pasting into the group.

In the mapping model, to select our scenario diagram canvas for the Related Diagrams reference, we need to use Load Resource again and load scenario.gmfmap into the resource set. Next, we create a new Child Reference to our Requirement Node Mapping and set its Containment Feature property to our new scenario:Process reference. The child Node Mapping settings are found in Figure 4-39. Unfortunately, when selecting the Related Diagrams property, a dialog appears with two Canvas Mapping entries. The scenario canvas should be the second one on the list, but we can do our usual verification by opening the model in a text editor.

We’re ready to re-create our requirements.gmfgen model using the normal sequence, but don’t generate the diagram code just yet. Open the generator model and navigate to the Gen Child Side Affixed Node ProcessEditPart element, where you can see the generated Open Diagram Behaviour element. The Diagram Kind property of the generated Open Diagram Behaviour element defaults to FIXME put GenEditorGenerator.modelID value here. Similarly, the Editor ID property defaults to FIXME put GenEditorView.id value here. We replace these with scenario and org.eclipse.scenario.diagram.part.
ScenarioDiagramEditorID
, respectively, as shown in Figure 4-40. Fortunately, these properties are preserved when updating the .gmfgen model. Note that if we planned to have multiple open diagram policies, we’d rename the default OpenDiagramEditPolicy to something such as OpenScenarioDiagramEditPolicy, to distinguish between them.

Figure 4-39 Scenario-related diagram mapping

Image

Figure 4-40 Scenario open diagram edit policy

Image

The string 'scenario' matches the semanticHints attribute of the Scenario diagram’s provider declaration, as shown next. When the ViewService is consulted to create the new diagram for the Process element reference, it uses this hint to create the diagram, as discussed in Section 10.4.4, “View Service.”

image

In the RequirementsEditor class, we need to add an adapter factory for our Scenario integration. The following line added to initializeEditingDomain() does the trick:

adapterFactory.addAdapterFactory(new
              ScenarioItemProviderAdapterFactory());

We now can regenerate our diagram code and launch. Add a new Scenario element to a Requirement in a sample diagram and double-click it. A new diagram should open in an adjacent editor tab, as shown in Figure 4-41.

Figure 4-41 Requirements diagram partition

Image

At the moment, we’re persisting a process model instance within our requirements model instance, contained within the associated Requirement instance. We could set the requirements.genmodel to use Containment Proxies, which would let us specify a new resource (file) for persisting new Process instances. This would also let us store these models independently and even initialize a new standalone scenario diagram for each process. This doesn’t work out of the box, but you can implement it using custom code.

4.5.7 Database Persistence

As mentioned in the overview of Modeling project components, we can persist models to other than a local file. Two components within the EMFT project allow for database persistence of EMF models: Teneo and Connected Data Objects (CDO). In this section, we use Teneo to persist our scenario diagram and domain model instance to a Derby database using Hibernate. The process for persisting both EMF models and GMF diagrams is presented in tutorials linked from the Teneo Web site, with the latter inspiring the content here.

After installing Teneo, we need to create plug-ins in our workspace that wrap the Hibernate and Derby libraries. This is as simple as adding empty plug-in projects and dropping the *.jar files from each into a /lib folder and setting up the manifest to include the archives and expose their packages. It’s also necessary to add an Eclipse-BuddyPolicy: dependent property in the Hibernate bundle manifest. In the scenario model plug-in, we can add dependencies to these plug-ins and to the org.eclipse.emf.teneo.hibernate plug-in, reexporting each.

With the dependencies established, we need to create an empty scenario database. The DataTools project makes this simple and is described in the tutorial. It’s a matter of configuring the Derby-embedded driver and declaring a path to where the database will reside. When the simple ping works, the database is ready for Teneo to use.

As in other diagram extensions, we create a separate org.eclipse.scenario.diagram.db plug-in to hold our additional classes required to enable database persistence. In the /src directory, we add a teneo.properties file that will contain the connection string information and Teneo options we need. These will ultimately be presented in the user interface, but for now we can simply use a properties file, as shown here. Adjust the driver_class, url, and dialect properties as necessary to match your environment.

teneo.mapping.inheritance = JOINED
hibernate.connection.driver_class=org.apache.derby.jdbc.EmbeddedDriver
hibernate.connection.url=jdbc:derby:/derby/databases/scenario
hibernate.connection.username=
hibernate.connection.password=
hibernate.dialect=org.hibernate.dialect.DerbyDialect

Because of the GMF notation model’s use of multiple inheritance, Teneo needs an additional annotations.xml file in the /src folder to map these elements to a relational store. This shows the contents of the file:

image

A curious feature in the notation model implementation requires another change for Teneo to function properly. See bug 159226 in Eclipse Bugzilla and the GMFEListPropertyHandler class in the sample project for more information. Hopefully by the time you read this, the bug will be resolved and the custom handler will no longer be required.

To initialize Teneo, we create a StoreController class. The class is provided in the sample project and comes largely from the original tutorial. You can easily generate this class and the remaining code required to use Teneo in combination with GMF using a decorator to the generator model and custom templates.

In the StoreController, a URI is defined using the datastore name and query using the hbxml scheme, which initializes a HibernateXMLResource class. In this case, our scenario data store is queried to load the Process element of the domain model and Diagram element of the notation model into the resource root.

public static final URI DATABASE_URI = URI.createURI(

“hbxml://?dsname=scenario&query1=from Process&query2=from Diagram”);

An instance HbSessionDataStore class is created and initialized as shown next in the contents of our initializeDataStore() method. The EPackages used include the domain model, the GMF notation model, the Ecore model, and the Ecore XML type model. The teneo.properties with connection information and annotations.xml are also loaded and used in the initialization. This method and the corresponding closeDataStore() method should be called from our plug-in Activator’s start() and stop() methods, respectively.

image

At this point, we need to write an action that will initialize our models and open our diagram editor. You can add the code found in the sample class OpenScenarioDBEditor to a wizard that enables the user to input the connection string information currently held in the teneo.properties file but for now is used in a simple action from the main menu. This code and corresponding contribution to the actionSets extension-point found in the sample project comes from the original tutorial.

Finally, some slight changes to the diagram editor are required because it expects to be working with file-based model resources. By overriding the following methods, the editor can accommodate the database resource that Teneo provides:

image

At this point, with our database created earlier, we can launch the runtime instance and open a new diagram using the DatabaseOpen Scenario Diagram menu. As with the file-based version, you can modify, close, and reopen the diagram. In fact, the two versions continue to function properly, although the database version presents some complications when working with transformations. With some custom code, you can overcome this by loading and exporting models from the database to a local file, or by modifying the invocation method for QVT, as the default launch configuration expects files.

Additional functionality is added to the scenario diagram in Section 10.9, “Extending Diagrams.”

4.6 Developing the Color Modeling Diagram

Our final sample application diagram is similar to a UML Class diagram, which gives us an opportunity to explore GMF compartment support for attributes and operations. We want this business domain modeling diagram to be simple, so we leave out some features of the UML and even object-oriented programming, such as navigability and strong aggregation. To begin, we need to consider how to represent the different archetypes using color. Starting with the figure gallery, we could create a distinct figure for each archetype and indicate the proper coloration. Unfortunately, this “hard-codes” the color and results in a fair amount of duplication, even if we use the Figure Ref element. We’d prefer a single archetype figure with a corresponding node in the graphical definition. Furthermore, we’d prefer to give users the opportunity to select the default shade of each archetype color using diagram preferences.

Concerning the mapping model, we know from our previous diagrams that adding constraints to node mappings determines their uniqueness and allows the canonical update of the diagram to function properly. If our domain model used a simple enumeration type to distinguish archetypes, we could initialize the value of the archetype’s type enum value using a Feature Seq Initializer. The problem is that the generated code will generate a figure class for each archetype, and by using the type enum in the constraint, a change of the value in the Properties will cause the view to be “orphaned” when the update takes place. A new view will be created for the element and placed by default in the upper-left corner of the diagram. This is clearly not what we want.

Another factor to consider with the enumeration approach is to map a single archetype node and hand-code changes in color based on enumeration value changes. This would greatly reduce the amount of generated code, but it leaves us wondering how often users would want to change an archetype type. If they did, the constraints and other factors we attribute to the archetype would have to change, potentially causing a ripple effect on connections and more. With the enumeration approach, to prevent users from changing the type, we could make the type attribute read-only in our EMF genmodel. In our case the domain model has a specific subclass for each archetype, making mapping straightforward and eliminating the need to provide feature initialization for each mapping. Furthermore, the generated code is much easier to deal with when using distinct subtypes for each archetype. As you’ll see, they generate EditPart names such as MomentIntervalEditPart instead of a series of ArchetypeEditPart, Archetype2EditPart, and so on, as is the case when using enumeration literals to distinguish type. We saw this in our Mindmap diagram when the Relationship class used an enumeration to distinguish among dependency, include, and extend types.

4.6.1 Diagram Definition

Unlike the previous diagram-definition models that referenced the domain model when creating a graphical definition, we can simply create a blank dnc.gmfgraph model in our /diagrams folder of the org.eclipse.dsl.dnc project by skipping the pages in the Graphical Definition Wizard that select a model.

As mentioned earlier, we can define a single archetype figure and node to be used for each of the mappings. Our archetype figures will use compartments for attributes and operations. Coloration and gradients will be accomplished using custom templates. Let’s start with our archetype definition, shown in Table 4-32.

Table 4-32 Archetype Figure Definition

Image

Image

Image

Our archetype figure is similar to a standard class figure. It has a name compartment and stereotype, although the placement of the stereotype is below the name in the case of our color modeling diagram. This is both to be different, and the result of a snag with applying gradients (discussed in Section 4.6.6, “Gradient Figures”). Note that we have defined ListItemLabel with an Inset element that keeps our attribute and operation compartment list items from aligning too close to the edge of the outer rectangle. We’ve done similarly in the outer rectangle, adding an Inset to keep the lowermost operation from being too close to the bottom of the rounded rectangle. Also note that our ListItem Diagram Label element has no Accessor selected, leaving its External attribute as true. Unlike other labels within nodes, selecting the BasicRectangle as the Diagram Label figure and adding a child accessor to the ListItemLabel Figure Descriptor causes the generated compartment to not function properly.

Also note our use of GridLayout and GridDataLayout elements throughout. These let us accomplish the layout of our archetype name and its stereotype label so that they remain centered in our rectangle. Our compartments for attributes and labels use basic rectangle figures. Note that we don’t bother setting their fill and outline properties to false because compartment figures defined will generate an extension of the runtime’s ResizableCompartmentFigure that takes care of rendering compartments properly. The EditPart generated will extend ListCompartmentEditPart, and the attribute and operation labels within these compartments will implement CompartmentEditPart, using WrappingLabel for the figure. Taking advantage of the runtime’s compartment support saves us some work because it provides proper layout, collapse, expand, and filtering functionality.

We also define a package figure and node, which is similar to the Archetype figure, aside from the fact that it uses a regular outer Rectangle and not a RoundedRectangle. Also, we’ll later map only one compartment to our package figure, to list subpackages. Because we have so much potential duplication in defining this figure, we turn to the Figure Ref element to avoid redundancy, as shown in Table 4-33.

Table 4-33 Package Figure Definition

Image

Clearly, using the graphical definition model’s Figure Ref element saves us a bit of work and encourages reuse. Moving on to our links, Table 4-34 gives the definitions of our Association and Aggregation connections. We use the Generalization link from the provided classDiagram.gmfgraph model, provided by GMF. We don’t need to reference it here—only in our mapping definition to follow.

Table 4-34 Generalization Link Definition

Image

Image

These connection definitions are straightforward, although you might have noticed that we don’t use link name labels in the diagram. We might add them later, but for now we want to keep our diagram as simple and uncluttered as possible.

The final elements that require definition at this point are the Annotation note and link. This time, we use a dashed line connection figure provided in the GMF classDiagram.gmfgraph model. To reference this or any other .gmfgraph model, right-click on the editor surface and select Load Resource from the menu. Enter the URI to the model in the dialog, as shown in Figure 4-42.

Figure 4-42 Load Resource dialog

Image

Table 4-35 gives the definitions of the annotation note figure and associated link. When selecting the Figure for the AnnotationLink Connection, you’ll find the DashedLineConnection now available, along with all other Figure Descriptors from our loaded classDiagram.gmfgraph model.

Table 4-35 Annotation Figure Definition

Image

Image

Notice again the use of the Figure Ref element. This time, we reuse the stereotype area and name area from our Archetype figure, but we list in reverse order because we want our Annotation to have a stereotype-like label at the top of the rectangle, with an area for the key and value below. As you can see, we chose a dashed line for the link to the annotation as well as for the rectangle outline. This lightens the appearance of the note, enabling us to focus on the annotation key and value, not to mention the color archetypes, which are the main focus points of the diagram overall.

This completes our initial graphical definition for the color modeling diagram. Next, we look at the palette definition.

4.6.2 Tooling Definition

Begin by creating a new dnc.gmftool model in the /diagrams folder using the provided wizard. You can use the Tooling Definition Model Wizard, as before, which enables you to derive tooling from the domain model. Or as in the graphical definition wizard, simply skipping the domain model selection pages results in an empty new model.

For the palette of our color modeling diagram, we group archetypes together and then stack the moment interval and moment interval detail within the group. We also stack our three “green” archetypes: party, place, and thing. You’ll find plug-in points and the package tool in this first tool group because they are main diagram nodes. Attributes and operations are listed next in their own group, followed by a group containing our association, aggregation, and generalization links. The most infrequently used tools are contained in the last group, where we put the annotation node and link. Figure 4-43 shows the palette definition next to an image of the palette itself.

Figure 4-43 Color modeling palette definition

Image

4.6.3 Mapping Definition

Create a new dnc.gmfmap model in the /diagrams folder using the Diagram Definition (Ctrl+3 → Diagram Def) Wizard. Select the dnc.ecore model as the Domain Model and for now select the Archetype class for the canvas mapping. We can’t select the oocore::Package element at this time because the wizard does not load the oocore.ecore model when selecting our dnc.ecore model. In the subsequent pages, select the dnc.gmftool and dnc.gmfgraph models as our tooling and graphical definition models, respectively. On the Mapping page, we can see another symptom of the wizard not resolving the oocore.ecore model. The list of discovered Nodes and Links is not what we expect, unfortunately. For now, just move the Association node to the Link side and remove the contents of the Links list. We need to correct our Canvas mapping and finish the remaining nodes manually.

With the dnc.gmfmap model open in the editor, adjust the Canvas Mapping to be as shown in Table 4-36.

Table 4-36 DNC Canvas Mapping

Image

We’ll return to our Association link mapping later. At this point, we enter a new Top Node Reference element to define the mapping for our moment interval archetype. Complete the mapping for this node according to Table 4-37. We’ll use this as the basis for all archetype mappings and use the Referenced Child property to avoid unnecessary duplication. This enables us to point to another node mapping that is already defined, rather than create another fully defined node mapping.

Table 4-37 Moment-Interval Archetype Mapping

Image

Image

* The use of the Feature Label Mapping element for our stereotype labels in all archetypes, package, and annotation mappings is a workaround for the fact that it’s not possible to leave the feature blank, or provide a default string value, if we want to use a regular Label Mapping or Design Label Mapping element. With the Read Only property set to true and the View Pattern set to the stereotype string we want displayed, it really doesn’t matter what feature is mapped, actually. This approach prevents us from having to create multiple label definitions in our graphical definition model and would likely cause us to create multiple archetype figure definitions.

Subsequent archetypes are mapped in a similar manner, each using the Referenced Child property, as mentioned earlier. Table 4-38 shows the mapping for the Role archetype; we don’t show the remainder, to save space. Only the mapped domain Element property of the Node Mapping, Creation Tool, and stereotype label View Pattern should differ for each archetype. In the case of the PluginPoint archetype, feature initializers for both the interface and abstract properties are set to true.

Table 4-38 Role Archetype Mapping

Image

The Package mapping is also quite similar, with the exception that it has only one compartment mapping and that it makes use of the diagram partitioning feature by specifying a Related Diagrams property, as you learned in Section 4.5.5, “Diagram Partitioning.” Including this mapping feature means that package elements on the diagram can be double-clicked to open a new diagram canvas to display the contents of the package. See Table 4-39.

Table 4-39 Package Mapping

Image

Annotations are mapped next. Note that we’ll again use the “phantom node” concept here because the annotation link determines the archetype that will contain the annotation. Although it’s possible to attach annotations to every model element, we provide for only archetype annotations at this time. Some complications arise when attaching links to compartment items. Table 4-40 shows the Annotation node and link mappings.

Table 4-40 Annotation Mapping

Image

Now we return to the Association link that the wizard created. Complete the mapping as shown in Table 4-41, taking note of the initialization of our element, including a Java initializer that we’ll need to provide code for later.

Table 4-41 DNC Association Mapping

Image

* The body of the generated method for a Java initializer can be provided in the model. Later, we’ll need to set the GenJavaExpressionProvider element’s injectExpressionBody property to true in our generator model for the following code to appear in our output. Note the use of fully qualified class names, which the generator cleans up.

image

For our Association element, we set a constraint based on the aggregation property to distinguish these links from our Aggregation links. We also initialize the aggregation property to false, set the bidirectional property to true, and create the opposite end Reference using the injected Java code above; after that, we set the name of the reference to the name of the opposite. An important side effect of using an Association to create an opposite Reference in this case is that we won’t get a duplicate link drawn, as would be the case if we specified a Reference type for the link. The reason is that no link mapping is defined for a plain Reference.

As you can tell, the links in the color modeling diagram remove a lot of the underlying complexity present in the domain model. Features are initialized to values that limit the range of modeling capabilities, keeping it simple for the Practitioner. We can expose more functionality in the future, but for now we will create bidirectional links and allow for only the specificity of target cardinality. Our Association class is not as powerful as what the UML provides, but that’s not the point of this diagram.

Our Aggregation link is similar to a regular association, except for the initialization of the aggregation property to true and the hollow diamond decorator at the source end. Another difference is with respect to link constraints, which here prevents aggregation relationships from being created to archetypes of differing type. The exception is the most common aggregation relationship in color models—that is, between a Moment Interval and a Moment Interval Detail. Table 4-42 shows the mapping.

Table 4-42 Aggregation Link Mapping

Image

Image

* Here’s the sad truth about creating a constraint to prevent aggregation links from targeting types other than the source—or, in the case of moment intervals, other than moment intervals or moment interval details. OCL gives us no simple solution, such as oppositeEnd.oclIsTypeOf(self). The reason is that the argument to oclIsTypeOf() must be a type literal, leaving us with this rather large expression:

image

Regarding Target End Constraint and Source End Constraint elements, it’s important to realize that these constraints are evaluated based on mouse position during the act of creating the link. For example, the source end constraint is evaluated when starting the link, so the context is that element. The oppositeEnd variable isn’t known yet, so don’t reference oppositeEnd in a source end constraint. Likewise, the target end constraint is evaluated when the mouse hovers over a target element when drawing the link. At this point, the oppositeEnd environment variable has a value.

Our final mapping is for the generalization link, shown in Table 4.43. Recall that we’ll be using the provided Connection from the classDiagram.gmfgraph model. Normally, we’d have to load this model using the Load Resource action, as done before in the graphical definition model. But because that model includes a reference to the classDiagram.gmfgraph model and is open in our mapping model resource set, the connection is already available to our mapping model.

Table 4-43 Generalization Mapping

Image

* As was the case with the Aggregation constraint, this is the verbose OCL constraint for generalizations:

image

The Link Constraints provide some important functionality to our link and to the Practitioner’s usability of our diagram. The first constraint allows only a generalization link to be drawn from an archetype that does not yet have a superclass. In this manner, we restrict the underlying metamodel to just one superclass. Also, we prohibit cyclic inheritance by applying a target end constraint that checks to see if the oppositeEnd of the link contains the source in its superclasses list. With that, we disallow generalization to one’s self. Finally, we prevent generalization relationships between archetypes of different types. In this approach to domain modeling, generalization is rarely used, and it doesn’t make sense to inherit from one type of archetype to another.

4.6.4 Generation

At this point, we’re ready to transform our mapping model into the generator model. Do this as before using the provided right-click menu action and corresponding wizard. If you find that the wizard cannot locate the dnc.genmodel file, use the Find in Workspace feature to locate the model and continue. Open the produced dnc.gmfgen model in the editor and change the Same File for Diagram and Model property to true, and change the Diagram File Extension property to dnc. Because our diagram allows for the creation of partitions to represent packages, it might be convenient to add shortcuts from archetypes in one package to another. Add the string dnc to the Contains Shortcuts To property in the Diagram category of the Gen Diagram element to provide shortcut support. Now we can run the diagram using our same launch configuration as before. Using the generated wizard, create a new DNC diagram and test its functionality. There’s no color yet, but all the elements should function. Notice that you cannot specify a data type for attributes at this time with the in-place editor. We address how this is done later when we add a custom parser for attributes in Section 4.6.6, “Custom Parsers.”

4.6.5 Gradient Figures

Our archetypes don’t currently have any color, which is their most significant attribute. Instead of simply filling in each archetype with a background color, we use a gradient effect. GEF enables you to add a gradient to a figure but does not directly support it. Don’t let that graphical definition model Gradient Facet element fool you—it is not yet implemented. Worse, this property is not available to the figure code-generation templates even if we did try to use it. So we’re left to find our own way to implement gradients in our archetypes, to give them a fresh appearance.

The fillShape() method of our archetype figure gives us the place to add a gradient. Simply overriding this method and adding a call to fillGradient() does the trick, except that gradients in GEF do not respect the corners of a RoundedRectangle figure. This effectively reduces our rounded rectangles to regular rectangles, though with gradient. Instead of spending time figuring how to implement gradients for rounded rectangles, we can be creative and adjust the starting point of the gradient to between the archetype name and the stereotype label. (Recall the hint earlier regarding the placement of these labels?) Not only does this give us a striking visual appearance, but it also has the effect of nearly eliminating the problems GEF in respect to the corners: The top no longer has gradient applied, and it’s faded enough by the bottom to make it hardly noticeable that it extends beyond the curve. Figure 4-44 is an example of the gradient, although the archetype does not yet define our foreground color. This illustrates the reason for the stereotype labels, however. Black-and-white print of our color diagrams makes it difficult to distinguish the archetypes otherwise. Additionally, the stereotypes let us distinguish between archetypes of the same color, such as Party, Place, and Thing, which are all green.

Figure 4-44 Color archetypes

Image

This is the code modification required to create the effect:

image

Now we need to generate this additional code for our archetype figures. We can leverage GMF’s capability to customize the templates for figure code generation. In case you’ve missed it each time, the dialog presented when transforming mapping to generator model has a “Provisional” section that gives us the field to enter the path to our custom templates, as seen in Figure 4-45.

Figure 4-45 Create Generator Model dialog

Image

The easiest way to get started modifying or augmenting GMF templates is to bring the appropriate *.codegen plug-in into the workspace. For figures, we’re interested in the org.eclipse.gmf.graphdef.codegen plug-in, so switching to the Plug-Ins view of our Plug-In Development perspective, we locate it and right-click, choosing Import AsSource Project. Browsing the contents of this plug-in, we discover the /templates/top/Figure.xpt Xpand template. This template provides an expansion of the Extras::extraMethods ≪DEFINE≫ that looks like just what we need to add our overridden fillShape() method. The Extras.xpt template contains this ≪DEFINE≫ block that we can use to create an ≪AROUND≫ that will add our method.

DEFINE extraMethods FOR gmfgraph::Figure-≫
ENDDEFINE

We create a /templates-figures/aspects/Extras.xpt template in our org.eclipse.dsl.dnc project. As discussed in Section 4.2.2, “Customization Options,” GMF uses the convention of prefixing the directory structure for aspects with a folder named aspects, followed by the original path to the template, as defined in the *.codegen project. In this case, we want to provide an aspect for the Extras.xpt template, which is located directly in the /templates folder. We’ll use the path /org.eclipse.dsl.dnc/templates-figures/ in the wizard dialog, as shown in Figure 4-45. When the generator finds the aspects folder, it will know to add this as an aspect template path.

Following is our template, which, as you can see, uses the polymorphic feature of Xpand to add our gradient code only for RoundedRectangle figures. We need to provide the obligatory ≪DEFINE≫ for the Figure supertype as well. Also note that we’re adding a useGradient Boolean to control whether to display gradients, which we can later hook up to a diagram preferences option.

image

We can again transform our mapping model to the generator model, adding our path to the figure template in the provisional GMFGraph Dynamic Templates field, and regenerate our diagram code. Recall that figures are serialized within the generator model by default, although we used the standalone figures method in the Scenario diagram that eliminates the need to regenerate all the diagram code to see the change. Figure 4-44 shows the result, with the remaining task of assigning the proper color for each archetype, based on its type. We want to avoid hard-coding this into our figures, which we mentioned when creating the graphical definition model. Instead, let’s see what is involved in adding color preferences for each archetype that the Practitioner can change, if desired.

4.6.6 Color Preferences

Basing the color of an archetype on its type is straightforward enough, and you can most easily accomplish this by overriding the setForegroundColor() method in each Archetype EditPart class. Recall that the gradient effect goes from our foreground to background color. For example, this simple implementation in our MomentIntervalEditPart class causes it to produce the desired gradient effect:

@Override
protected void setForegroundColor(Color) {
    super.setForegroundColor(new Color(null, 250, 145, 145)); }

We need to do a bit more for the color to be obtained from the diagram preferences, and for diagram elements to respond to changes in the default values. Plus, we again want to modify our code-generation templates so that these changes will not be overridden if we forget to add the appropriate @generated NOT tag, or if we need to delete and regenerate our diagram plug-in entirely.

This time, we need to import the org.eclipse.gmf.codegen plug-in into our workspace as a source project, just as we did for the org.eclipse.gmf.graphdef.codegen plug-in earlier. You will find a lot of templates and extension files in this project, so consider it a resource for understanding how to use Xpand, not to mention how to modify GMF generation. Another good source of examples for working with GMF, custom templates, and extensions is the UML2 Tools project. Looking at our generated diagram code, we see that the DiagramAppearancePreferencePage class is the best location for our archetype color preferences. Currently, this page provides default font, line color, and fill color preferences, among others. We can add another group for archetype color preferences below the existing group.

As before, we first code our changes manually and then “templify” the changes in our custom templates. Looking at the AppearancePreferencePage superclass of this preference page, we see that adding our own group and color defaults should be straightforward. Using copy and paste, we insert the following code into our diagram’s preference page, which started as a simple subclass designed for extension. Note that we override the addFields() method to allow for the addition of the archetype color group. To save space, some repetitive code is commented out.

image

image

To provide for localization, we add the strings just referenced to our Messages class and to the diagram plug-in’s messages.properties file. Note that the default values for each archetype color are provided previously, in RGB. To initialize the preferences, we look to the generated DiagramPreferenceInitializer class. We need to have the initializer call our initArchetypeDefaults() method, provided earlier, as shown in the modified implementation here:

image

These are the additions made to the org.eclipse.dnc.diagram.part.Messages class:

image

And these are the additions we made to the messages.properties file:

image

At this point, we can launch our diagram and see the properties in action, although they have no effect on the diagram because they’re not incorporated into our EditPart code yet. Again, using black-and-white images does little to illustrate the use of color modeling, as seen in Figure 4-46.

Figure 4-46 Archetype color preferences

Image

Turning finally to our EditPart code, we use MomentIntervalEditPart as our testbed. Adding the following code makes our preferences-based color options functional. To begin, we add an inner class, PreferencePropertyChangeListener, that will detect a change in the appropriate property and invoke the updateArchetypeColor() method. To initialize and register this listener, we override the addNotationalListeners() method.

image

The overridden setForegroundColor() method and the preference listener both obtain the appropriate color from the preference store, as shown in getPreferenceColor(). All that’s left to do is test the functionality and then move on to templatizing the code changes. One improvement might be to restrict the color ranges for each archetype so that they still maintain their pink, yellow, green, or blue essence.

We begin our GMF diagram template spelunking in the /templates directory of the imported org.eclipse.gmf.codegen plug-in. We notice right away that there are three editparts directories: one under /templates/diagram, one under /templates/impl/diagram, and one under /templates/xpt/diagram. The last one is a legacy structure and should be ignored in favor of the /templates/impl pattern to distinguish published API vs. non-API templates. Looking into each and finding a NodeEditPart.xpt template in the first two, we open each to see the differences. In the /templates/diagram/editparts/NodeEditPart.xpt template, we see that it delegates to the /templates/impl/diagram/editparts/
NodeEditPart.xpt
template for generation of the class content. What interests us most, however, is the ≪EXPAND additions-≫ expansion near the end of the class. All we need to do is add the code listed earlier to our archetype EditPart classes, so this looks like a promising place to start. In fact, this expansion was designed for Toolsmiths to use for customizing the generated code, and you’ll find many of them in the GMF templates. The corresponding ≪DEFINE≫ block appears at the bottom of the template and is listed here:

DEFINE additions FOR gmfgen::GenNode-≫
ENDDEFINE

We need to create a NodeEditPart.xpt template file in our org.eclipse.dsl.dnc project in a /templates/aspects/diagram/editparts folder. Again, we conform to the GMF convention of aspect template placement so that the generator will invoke our template. We place an ≪AROUND≫ block at the top of the template, as follows:

image

As you can see, we’re breaking up the implementation into a series of ≪DEFINE≫ blocks, each corresponding to a method. This is another best practice for using Xpand, and one you’ll see throughout the GMF templates. Note, however, that the context for this custom template remains gmfgen::GenNode. This means that all EditPart classes that are generated for nodes will have these customizations added, not only archetypes. Our diagram has two other types of nodes, package nodes, and annotations. This doesn’t present a problem in our case because we default all nodes not recognized as archetypes during execution as the plug-in point archetype. The ≪EXTENSION≫ at the top of our template points to our Util.ext file that contains the logic used, as shown here:

image

You’ll see where this function is invoked shortly, but it’s clear from this how each archetype is mapped to its corresponding preference constant. The first template definition invoked appears next and simply adds a field for our inner PreferencePropertyChangeListener class. Note the use of the xpt::Common::generatedMemberComment and xpt::Common::generatedMemberComent expansions throughout the template, which insert the familiar @generated tags above class, field, and method declarations.

image

Next, we define the listener class itself, which, as you can see, needs to access the fully qualified class name for our generated appearance preference page. This listener class is the first to use our toPreferenceConstant() function for the passed archetype.

image

Note the navigation to the archetype’s Ecore class using modelFacet.metaClass.ecoreClass in the statement. The structure of the GMF generator model is important to have handy when writing templates, and you can easily open it from the imported project, or simply open the QVTO Metamodel Explorer for navigator view access to the model. As you saw in the utility function, the name of the class maps to its preference constant, which is inserted in the generated code so that the EditPart can detect changes to its color preference. We could use a variation of this logic to avoid generating this color preference code for non-archetype nodes.

The rest of the template definition appears here. It’s a straightforward templating of our handcrafted code, with the only other noteworthy aspect being the use of toPreferenceConstant() again in the getPreferenceColor definition block.

image

Moving on to the preference page templates, we find the original AppearancePreferencePage.xpt template in /templates/xpt/diagram/preferences. We need to override this template, along with PreferenceInitializer.xpt, because they were apparently not created with extensibility in mind, as was the case with the NodeEditPart.xpt template. This means that we simply copy these two templates into our own /templates-diagram/xpt/diagram/preferences folder and modify them to suit our needs. Most of the changes required for the preference page code is straightforward copy and paste from our earlier handcrafted code, so we don’t repeat it here. However, we do need to explore how GMF deals with globalization because we need to add referenced elements to our generated Messages class and messages.properties file. Looking at the template files, we find an Externalizer.xpt template in the /templates/xpt folder in the generator plug-in. The Externalizer template provides a centralized means by which to generate the Messages class and properties file. The template is organized in two main definition blocks, as shown here. Basically, GMF convention is to declare an i18nAccessors and i18nValues definition in templates that require localization and invoke them from the Fields and Values definitions, respectively.

image

We follow suit with our properties preference page by defining similar blocks for invocation by our overridden Externalizer.xpt template. First, we take a look at the externalizer, which is placed in our /templates-diagram/aspects/xpt directory.

image

Here, we create ≪AROUND≫ aspects for both the Fields and Values definitions, expand our custom template definitions, and then continue execution of the original template using targetDef.proceed(). This is a common approach to extensibility using Xpand. Back in our AppearancePreferencePage.xpt template, we find the definitions.

image

When the Messages class and messages.properties files are being generated, each template that requires messages is invoked and the strings are added to these files. You need to go to the i18nValues blocks for declaring the default localized string values when using GMF Xpand templates. Two callback expansions are made from the template to messageEntry and accessorField in the Externalizer.xpt template, as shown here. The first creates a public static String entry in the generated Messages class file; the second creates a key=value entry in the messages.properties file.

image

Having provided a means by which to produce messages, we now need to access them in our generated code; this means examining another aspect of GMF’s Externalizer.xpt template. When a message is accessed in the code generated, it needs to resolve the Messages class, which means calling back again to the Externalizer.xpt template so that the fully qualified path can be provided. Following is the accessorCall definition, used for just this purpose.

image

We use this in our preference page template, as shown here:

image

Our final template required to provide full generation of our preferences-based archetype color feature is the PreferenceInitializer.xpt template. As mentioned earlier, the only change required to this template is to add an invocation of the initArchetypeDefaults() method, as shown next. This template contains a good deal of code that we do not require, but for now we’ll leave it as is and make our single modification.

image

We need only to set the Dynamic Templates property of our Gen Editor Generator root element in our dnc.gmfgen model to true, and enter a Template Directory path of /org.eclipse.dsl.dnc/templates-diagram. Regenerating our code should produce code that runs and, for the first time, renders each archetype according to its default color. Experiment with the preferences to ensure that they work and to find a set of RGB values that you find most appealing. Perhaps the best outcome of this template exercise, other than a better understanding of how GMF’s code generation works, is knowing that you can delete and fully generate this feature in your diagram plug-in.

4.6.7 Custom Parsers

A popular feature of class modeling tools is the capability to specify the type after the name when entering attributes, or even complete method signatures, using the in-place editor. For our DNC diagram, we begin with the attribute field. Currently, we enter the name of the attribute using the diagram, but then we need to drop down to the properties view to select the type, which doesn’t display on the diagram. We can take two basic approaches to solving the problem. One is to contribute to the parserProviders extension-point in the diagram or custom plug-in and implement our own IParserProvider. Another approach is to use the Feature Label mapping in the dnc.gmfmap model to generate code that we could modify to complete the implementation. Because we require custom parsers for our Attribute and Operation labels, we use both approaches, to illustrate the differences.

Attribute Parser Provider

For attributes, we want to enter name:Type in the label on the diagram and have it parsed properly to set the name and dataType fields of the underlying Attribute domain element. Of course, we want the label to display name:Type even when changes are made to the underlying model through the properties view, for example. To begin, we create a new (empty) org.eclipse.dnc.diagram.custom plug-in to our workspace and contribute to the parserProviders extension-point, as follows:

image

We need to provide the AttributeParserProvider class, which extends the runtime’s AbstractProvider and implements the IParserProvider interface. This is the class, which still could use some optimization but works well enough for now:

image

image

image

image

Starting at the bottom, we find that the IProvider.provides() method returns true if the GetParserOperation passed contains a hint that resolves to the AttributeEditPart’s visual ID and an instance of our Attribute class. With this parser provider registered as a service provider, its getParser() method is invoked to supply an implementation of ISemanticParser. The implementation of the parser is crude, but it functions adequately for our sample. Notice that it loads all models in the resource set that are looking for Datatypes to validate against. The idea with types is that a types.oocore, or similar, is provided and loaded automatically, or users are given the option to load their own types. The most important aspect of the parser is the getParseCommand() method. As with all model modifications that take place within the context of a GMF application, a transactional command is used within the editing domain to effect the change.

Operation Parser Provider

Our Operation parser provider needs to be slightly more complex than our Attribute parser provider, given the relative complexity of an Operation signature. We need to take into account the name of the operation, the return type, and each parameter name and type. As usual, we surround our parameters with parentheses and delimit them with commas. Types are followed by a colon for both parameters and return type—for example, calculatePriceForQuantity(item:Item, qty:Integer):BigDecimal.

For our Attribute example, it was reasonable to implement the parser provider by hand, given that we had to deal with only two values. For more complex parsing, such as that required for our Operation parser provider, we really should define a grammar and use a parser generator to do the heavy lifting. In fact, looking again to the UML2 Tools project for examples, we find that JavaCC was used to produce parsers for UML operation fields, among others. This book does not provide the details of the implementation, but they are provided within the sample projects, including documentation throughout.

4.7 Summary

In this chapter, we explored in some detail the process of working with GMF to define a series of domain-specific diagrams. As the possible functionality of a diagramming surface may be quite extensive, we covered only some of the most popular use cases in this chapter, leaving detail about the tooling and runtime components to Chapter 11 as reference for adding your own functionality.

At this time, we move on to discuss a bit about the development of textual concrete syntaxes for our domain-specific languages.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.180.111