Channels ▼
RSS

Tools for Domain-Specific Modeling

Source Code Accompanies This Article. Download It Now.


September, 2004: Tools for Domain-Specific Modeling

Generating code from models

Steven is chief technical officer at MetaCase. He can be contacted at steven.kelly metacase.com.


By generating full code directly from models, domain-specific modeling (DSM) uses graphical modeling languages to build narrow ranges of applications 5-10 times faster than hand coding. To date, however, the only way of doing this that works is to make both the modeling language and generators domain specific. Attempts at completely generic modeling languages and generators haven't succeeded because raising the level of abstraction always means sacrificing fine control and complete generality, for the more important end of productivity.

Different camps have different views on just how specific DSM languages should be. At one end of the scale, the OMG (http://www.omg.org/) would like everyone to use unadulterated UML. However, the OMG has tacitly admitted that full code generation from UML is not going to happen, and is pinning its hopes on model-driven architectures (MDA). At its most basic, this involves transforming one UML model into another UML model, possibly several times and possibly automatically, then automatically generating substantial code from the final model. MDA proponents envisage higher forms of MDA incorporating elements of DSM, and these may offer hope. In these, the base UML can be extended with domain-specific enhancements, or even replaced with metamodels based on Meta Object Facility (MOF), a UML subset intended for use as a language for describing modeling languages. However, my experiences with the former have revealed that current tools lack the necessary extensibility, and no tools support the latter.

In short, UML is not domain-specific, and trying to build domain-specific models in a UML tool is, at best, like trying to write English in a Spanish version of Word. The GUI labels are all wrong, and the tool keeps trying to correct your input into something valid for its language. Moreover because the tool is parsing your input according to the wrong language, any attempt at translation or code generation will be fraught with difficulties.

This explains in part the lack of adoption of DSM, despite its promise—existing CASE tools simply cannot support it. Without tool support, any modeling language is largely useless, and certainly no code can be generated. Building a CASE tool for your own modeling language is prohibitively expensive. Even for a simple language, full CASE support would take man-years to build from scratch.

That is where tools for building DSM editors come in. These tools let you build a completely new modeling language, editor, and code generator for a domain. The tools can be divided into two classes—code frameworks such as Eclipse's EMF and GEF and metaCASE tools such as MetaEdit+ from MetaCase (the company I work for). The frameworks are just that: pure code, with utility functions and classes useful for building graphical CASE tools. On the other hand, metaCASE tools implement generic graphical CASE behavior, and users supply the concepts and symbols via the tool's GUI.

EMF & GEF

While the main focus of Eclipse has been on its IDE for Java programmers, two major Eclipse tool projects offer help for modelers, too. The Eclipse Modeling Framework (EMF) lets you input your desired data model, then generates table-based editors and an XMI schema for such models. The Graphical Editor Framework (GEF) supplies functions and classes useful for specifying graphical editors for Eclipse data. Although you can use EMF and GEF separately, building DSM support requires both—and, of course, Eclipse. There is no support for building standalone editors.

The main function of EMF (http://www.eclipse.org/emf/) is to provide a data entry and storage environment following a schema that you supply. EMF does not use the OMG MOF standard, although the design of the Ecore data model (a metamodel for describing models and runtime support and reflective API for manipulating EMF objects) it uses was influenced by MOF. In the EMF team's experience of building modeling tools, MOF was found to lack necessary features.

Your schema, or metamodel, can be fed to EMF in several formats. The native format is an XMI file, but EMF can also read Rational Rose class models, annotated Java files, or XSD files, providing these follow its restrictions.

Based on this input, the EMF.Codegen code generator facility can generate a bare bones editor for data following the schema. The editor uses classes from the EMF.Edit framework to provide standard table and property sheet views. If the generated editor is not sufficient, you can add your own code. Providing it is marked correctly, the generator will not overwrite your code when the schema is updated, although neither will it update it to reflect the schema changes.

You can also build your own code directly on top of the EMF.Edit framework, and that indeed seems to be the way many developers go. For instance, a Norwegian telecom project (http://www.pats.no/) has been working on cellphone service engineering. The original solutions used a State Machine pattern with both state actions and legal transitions hand-coded in Java. To reduce the work and improve the chances of validating the resulting system, they wanted to have the state machine represented in a model. For the simpler parts of the system, they were able to use the EMF-code-generation framework on annotated Java and even an existing XSD file. For the more table-based state editor, they are hand-coding on top of the EMF.Edit framework. Currently, that part is 4000 lines of code and requires about another three months' work. The rest of the editors and property sheets are another few thousand lines of code with significant parts generated. In total, the project has taken about six man-months so far.

EMF only provides part of the solution for DSM—data storage, property sheets, tree, or table-based browsing, and a code generation framework. GEF (http://www.eclipse.org/gef/) provides the graphical support needed for building a diagram editor on top of the EMF framework. Diagrams bring two vital additions to the modeling experience. First, the human brain is better at quickly interpreting and remembering a graphical diagram than text, trees, or tables. Second, diagrams show multiple relationships between objects much better than text or table formats. While a tree format can show one simple kind of relationship well, it cannot handle object reuse or other relationships.

GEF is not particularly designed to take advantage of EMF. The only thing they really share is their integration with the Eclipse change notification. GEF uses a Model-View-Controller pattern, where the Model can be an EMF model or something entirely different. While using GEF, the intention is thus that the Model is largely ignored and the main work happens in the Controller. Such a heavy Controller in an MVC framework is somewhat unusual. In many ways, it might have been better to establish an MVC framework entirely within GEF, with its own true Model to represent facts like the coordinates of a model element. This graphical Model could then have received change notifications from the EMF model.

The GEF Controller is called an "EditPart" and, for each EMF model element class, you normally need to create a corresponding EditPart class. EditParts have a Figure, which is their graphical view, implemented in the lower level Draw2D graphical framework. Designing a symbol for your DSM language thus consists of writing Java code for its individual lines and curves, which can be painstaking work. Often, a second Figure is necessary for display when a model element is being moved; for example, to show the symbol grayed out.

EditParts respond to events by way of an EditPolicy: Most EditParts require their own EditPolicy class. The job of the EditPolicy is to turn the event request into a Command. GEF uses the Command pattern to implement an undo stack—all changes to data must happen through Commands, and each Command must store its own undo information on the stack and implement an undo method. Unfortunately, while EMF also has the same pattern, they are implemented in different namespaces and cannot be used together. Instead, you must maintain EMF undo information separately from GEF undo information, and try to maintain consistency between them.

MetaEdit+

MetaEdit+ was built on the principle that all CASE tools are essentially the same—you can put objects on a diagram, fill in their properties, connect them with relationships, and move them around. All that really changes between different modeling languages is what the object types look like, what properties they have, and how you can connect them.

The MetaEdit+ toolset includes generic CASE behavior for objects and relationships, including a Diagram Editor, Object and Graph Browsers, and property dialogs. DSM developers need only specify their modeling language: for example, creating a new object type, giving it a name and choosing which property types it has. A vector-based Symbol Editor lets you define your object and relationship symbols or reuse existing symbols. There is no need for hand coding, nor is any CASE tool code generated. The MetaEdit+ editors simply follow the defined language in a similar way to how Word follows its templates.

In addition to the CASE editing functionality, MetaEdit+ includes XML import and export capabilities, an API for data and control access to MetaEdit+ functions, and a generic code generator. The code generator uses a domain-specific language (DSL) that lets you specify how to walk through models and output their contents along with other text. This makes defining code generators straightforward, with one line of a code generator definition corresponding to several lines in the scripting languages sometimes used for this purpose. As the generator has no preconceptions about the modeling language, code language, or framework the code runs on top of, you have complete freedom to produce the best code possible from the models.

Comparison

For comparison, I rebuilt an Eclipse sample application—a simple Logic Gate DSM language (available electronically; see "Resource Center," page 5) that lets you connect AND, OR, and XOR gates and link them to form circuits with LED displays and voltage sources (Figure 1). The example is pure GEF, with no EMF for data storage or editing (there were essentially no data values to edit).

While there was no code generation from the Logic models, about 5 percent of the code added on some simulation behavior. A connection wire could show its true/false status by changing color, and an LED display could show the values of its inputs. In a normal DSM scenario, it would be more likely that code could be generated from the model, and running that code could show the values with different input conditions.

The GEF Java code for the sample was 332 KB (120 files, over 10,000 lines). Listing One presents part of the code for the LED display type definition, while Listing Two shows part of its display code. To make a cleanroom implementation in MetaEdit+, I looked at the resulting editor rather than its Java code. The basic concepts of the DSM language were clear from the type palette, and by playing with the example model, I found out how the gates could be connected. For instance, there was a distinction between in and out ports on each gate, and connections had to be from an out port to an in port. These kinds of rules are one thing that distinguishes DSM editors from drawings in PowerPoint or Visio.

It took about 15 minutes to specify the eight object types along with their port and connection types and rules. With my limited graphical skills, drawing and fine-tuning the symbols in the MetaEdit+ Symbol Editor took an additional 45 minutes. Figures 2(a) and 2(b) show the LED object type and symbol definitions. The total of one hour included building the same example model as in Eclipse: a useful step in MetaEdit+, which lets you test a language while building it.

The resulting editor (Figure 3) was essentially identical to that in GEF, apart from omitting the simulation behavior. That could be added using the MetaEdit+ API with no more code than it took in GEF. Graphical behavior in MetaEdit+ was somewhat better, as connections followed objects as you dragged them (GEF showed only the object outlines while dragging). MetaEdit+ also included all its other behavior: browsers, XML import/export, HTML and Word export, multiuser repository, and so on.

Conclusion

The EMF framework offers a good solution if you want to add a measure of non-graphical modeling into the already strong Eclipse development environment. GEF is a good basis for organizations wanting to build a graphical editor that does not follow the normal pattern of CASE tool behavior; for example, a GUI design tool. By also supporting such behavior, however, it misses the chance to offer optimal support for standard CASE behavior. In short, CASE tools can be built with GEF, but the amount of coding necessary isn't insignificant.

DDJ



Listing One

/* Abridged version of LED.java, showing parts related to property value.
 * Whole file is 3 times as long. In total, the 4 LED classes are 663 lines.
 */

package org.eclipse.gef.examples.logicdesigner.model;

import org.eclipse.gef.examples.logicdesigner.LogicMessages;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.PropertyDescriptor;
import org.eclipse.ui.views.properties.TextPropertyDescriptor;

public class LED
    extends LogicSubpart
{
public static String P_VALUE = "value";  
protected static IPropertyDescriptor[] newDescriptors = null;
static{
    PropertyDescriptor pValueProp = new TextPropertyDescriptor(P_VALUE, 
            LogicMessages.PropertyDescriptor_LED_Value);
    pValueProp.setValidator(LogicNumberCellEditorValidator.instance());
    if(descriptors!=null){
        newDescriptors = new IPropertyDescriptor[descriptors.length+1];
        for(int i=0;i<descriptors.length;i++)
            newDescriptors[i] = descriptors[i];
        newDescriptors[descriptors.length] = pValueProp;
    } else
        newDescriptors = new IPropertyDescriptor[]{pValueProp};
}
public Object getPropertyValue(Object propName) {
    if (P_VALUE.equals(propName))
        return new Integer(getValue()).toString();
    if( ID_SIZE.equals(propName)){
        return new String("("+getSize().width+","+getSize().height+")");
    }
    return super.getPropertyValue(propName);
}
public void resetPropertyValue(Object id){
    if (P_VALUE.equals(id))
        setValue(0);
    super.resetPropertyValue(id);
}
public void setPropertyValue(Object id, Object value){
    if (P_VALUE.equals(id))
        setValue(Integer.parseInt((String)value));
    else
        super.setPropertyValue(id,value);
}
}
Back to article


Listing Two
/* Abridged version of LEDFigure.java, showing just unselected symbol display.
 * Whole file is 4 times as long, plus 65 lines for dragged symbol display.
 */
protected void paintFigure(Graphics g) {
    Rectangle r = getBounds().getCopy();
    g.translate(r.getLocation());
    g.setBackgroundColor(LogicColorConstants.logicGreen);
    g.setForegroundColor(LogicColorConstants.connectorGreen);
    g.fillRectangle(0, 2, r.width, r.height - 4);   
    int right = r.width - 1;
    g.drawLine(0, Y1, right, Y1);
    g.drawLine(0, Y1, 0, Y2);
    
    g.setForegroundColor(LogicColorConstants.connectorGreen);
    g.drawLine(0, Y2, right, Y2);
    g.drawLine(right, Y1, right, Y2);

    // Draw the gaps for the connectors
    g.setForegroundColor(ColorConstants.listBackground);
    for (int i = 0; i < 4; i++) {
        g.drawLine(GAP_CENTERS_X[i] - 2, Y1, GAP_CENTERS_X[i] + 3, Y1);
        g.drawLine(GAP_CENTERS_X[i] - 2, Y2, GAP_CENTERS_X[i] + 3, Y2);
    }
    // Draw the connectors
    g.setForegroundColor(LogicColorConstants.connectorGreen);
    g.setBackgroundColor(LogicColorConstants.connectorGreen);
    for (int i = 0; i < 4; i++) {
        connector.translate(GAP_CENTERS_X[i], 0);
        g.fillPolygon(connector);
        g.drawPolygon(connector);
        connector.translate(-GAP_CENTERS_X[i], 0);
        
        bottomConnector.translate(GAP_CENTERS_X[i], r.height - 1);
        g.fillPolygon(bottomConnector);
        g.drawPolygon(bottomConnector);
        bottomConnector.translate(-GAP_CENTERS_X[i], -r.height + 1);
    }
    // Draw the display
    g.setBackgroundColor(LogicColorConstants.logicHighlight);
    g.fillRectangle(displayHighlight);
    g.setBackgroundColor(DISPLAY_SHADOW);
    g.fillRectangle(displayShadow);
    g.setBackgroundColor(ColorConstants.black);
    g.fillRectangle(displayRectangle);
    
    // Draw the value
    g.setFont(DISPLAY_FONT);
    g.setForegroundColor(DISPLAY_TEXT);
    g.drawText(value, valuePoint);
}
Back to article


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video