/ Planet KDE

How cute can modeling be ?

Heya planet,

It's been a long time since my last post (as usual :) - hopefully that's going to change in next months). A lot of things have happened in QtModeling land though. In case you haven't read my previous call for arms and XMI serialization and metamodel plugins posts, QtModeling is intended to provide a complete and flexible infrastructure for software (meta)modeling, (automated) architecture design and analysis, model recovery, and whatever comes in mind when you think about software models. Although we are still far from have those features fully available, some interesting capabilities are quite functional.

MOF/UML Metamodel Implementation

The new refactored templates for automatic metamodel implementation make programmatic model manipulation easier by taking ownership of properties with 'composite' aggregation and automatically removing elements from all involved property lists when it's deleted. While Qt properties features described in QTBUG-17301 are still being considered, QtModeling extends Qt property system by defining roles for aggregation, opposite association ends, redefined and subsetted properties, and derived and derived union constructors. Some UML functionalities defined as derived properties/operations still miss implementation but basic features involving class and components diagrams are already in place. XMI serialization, profiles and stereotypes definitions/applications, and imported elements/packages are also currently available.

When building QtModeling, the following Qt Add-ons modules will be available:

  • QtModeling: defines base classes for model elements (QModelingElement and QModelingObject) and QXmiWriter/QXmiReader classes for XMI serialization.
  • QtModelingWidgets: provides two new model classes (QModelingObjectModel and QModelingObjectPropertyModel) and two new view classes (QModelingObjectView and QModelingObjectPropertyEditor) for manipulating models and model element's properties.
  • QtUml: implements the full UML 2.4.1 metamodel. It comprises 239 classes which are 91.83% automatically implemented by templates. The remaining code represents derived properties and are being implemented on demand.
  • QtMof: implements the full MOF (Meta Object Facility) 2.4.1 metamodel. It comprises 51 classes also almost entirely implemented automatically.
  • QtDuSE: implements the DuSE language/metamodel (part of my PhD research) for automated software architecture design and analysis.
  • QtSADuSEProfile: defines an UML Profile for automated software architecture design of self-adaptive systems. This is required by SADuSE - a specific DuSE design space instance devoted to self-adaptive systems design.
  • Qt metamodel plugins: bind the previous model modules as Qt plugins used during XMI serialization.

DuSE-MT

DuSE-MT is a software modeling framework built on top of QtModeling which provide underlying mechanisms for defining new modeling languages (metamodels), creating models described in available languages (currently UML, MOF, and DuSE), manipulate models via JavaScript, and basic constructs for UML diagrams.

![DuSE-MT](/content/images/2015/07/dusemt.png)

DuSE-MT defines a plugin-based architecture (shamelessly :) inspired by Qt Creator's one), which supports not only Qt metamodel plugins but also extensions implementing new DuSE-MT functionalities such as concrete syntax handling, architecture recovery, automated architecture design, and so on. One of the good things of being a professor is to have students eager to graduate :) and willing to do their final projects in some Qt/KDE related project. Let's see what happens ...

![DuSE-MT Plugins](/content/images/2015/07/dusemt-plugins.png)

Model Scripting

DuSE-MT's JavaScript Console allows for defining scripts which might, for example, verify well-formedness rules and/or extend/change the currently opened model. For instance, if you know in advance you are going to use Java to implement the currently modeled system, you might use the following script to verify if any multiple inheritance was found in your model:

![DuSE-MT JavaScript Console](/content/images/2015/07/dusemt-javascript.png)

While a full OCL parser isn't already available, such kind of scripts can be really useful (actually it's even more expressive than OCL since it's not limited to read-only operations).

QML for UML Concrete Syntax

It's really amazing how QML seems to be born to make certain things real without much pain :) Even in such highly dynamic cases with many requirements for integrating with C++ objects, QML property binding and some new defined QML items can rapidly gives you some nifty diagrams:

![DuSE-MT UML Concrete Syntax](/content/images/2015/07/dusemt-concretesyntax.png)

Wondering how much QML code was required to do that ? Here it is:

import QtQuick 2.0  
  
UmlElement {  
    UmlSlot {  
        id: nameSlot  
        anchors.top: parent.top  
        Text {  
            id: label  
            text: element.name  
            anchors.centerIn: parent  
        }  
    }  
    UmlSlot {  
        id: attributeSlot  
        anchors { top: nameSlot.bottom; topMargin: -1 }  
        height: (parent.height - nameSlot.height)/2  
        ListView {  
            model: element.ownedAttributes  
            anchors { fill: parent; margins: 4 }  
            delegate: Text {  
                text: visibility(modelData.visibility) + modelData.name + ": " + (modelData.type ? modelData.type.name:"<no type>")  
            }  
        }  
    }  
    UmlSlot {  
        anchors { top: attributeSlot.bottom; topMargin: -1; bottom: parent.bottom }  
        ListView {  
            model: element.ownedOperations  
            anchors { fill: parent; margins: 4 }  
            delegate: Text {  
                text: visibility(modelData.visibility) + modelData.name  
            }  
        }  
    }  
    function visibility(visibilityEnum)  
    {  
        switch (visibilityEnum) {  
        case 0: return " "  
        case 1: return "+"  
        case 2: return "-"  
        case 3: return "#"  
        case 4: return "~"  
        }  
    }  
}  

... and for UML associations:

import QtQuick 2.0  
import QtModeling.Uml 1.0  
import "util.js" as Util  
  
Relationship {  
    name: element.name  
    relationshipType: "association"  
    source: Util.findQuickItem(parent, element.memberEnds[0].class_.name)  
    target: Util.findQuickItem(parent, element.memberEnds[0].type.name)  
    sourceAggregation: aggregation(element.memberEnds[0].aggregation);  
    targetAggregation: aggregation(element.memberEnds[1].aggregation);  
    sourceMultiplicity: element.memberEnds[0].lowerValue.value + ".." + element.memberEnds[0].upperValue.value  
    targetMultiplicity: element.memberEnds[1].lowerValue.value + ".." + element.memberEnds[1].upperValue.value  
    function aggregation(aggregationEnum)  
    {  
        switch (aggregationEnum) {  
        case 0: return "none"  
        case 1: return "shared"  
        case 2: return "composite"  
        }  
    }  
}  

... where Relationship is a new QML item we implemented based on QPainter API (I still need to learn how to use the new SG API). With such things done, UML concrete syntax implementation becomes the simple creation of QML files with names matching the corresponding UML metamodel element (UmlNode, UmlState, and so on).

QtOptimization

Supporting automated architecture design involves, among other things, the use of some search-based approach to find out several candidate architectures and then choose one that satisfies some specific quality attribute criteria. Elitist population-based algorithms have been successfully applied in such scenario because of their improved performance and fast convergence. If you've already played before with JMetal or some other framework for multi-objective optimization, that's exactly what QtOptimization is intended to be. Currently, only NSGA-II (Nondominated Sorting Genetic Algorithm) is implemented (QNsga2 class), in conjunction with classes for bitwise mutation (QBitwiseMutationOperator), crossover (QCrossoverOperator), polynomial mutation (QPolynomialMutationOperator), simulated binary crossover (QSbxCrossoverOperator), and tournament selection (QTournamentSelectionOperator) operators.

Here is a brief description on how to use QtOptimization for a single-variable/two-objective optimization problem:

// Define objective function 1  
class MyObjectiveFunction1 : public QObjectiveFunction  
{  
public:  
    explicit MyObjectiveFunction1(QtOptimization::OptimizationGoal optimizationGoal = QtOptimization::OptimizationMinimizes) :  
        QObjectiveFunction(optimizationGoal) {}  
    virtual qreal evaluateOnIndividual(const QIndividual *individual) const  
    {  
        qreal x = individual->realVariableValue(0);  
        return x*x;  
    }  
};  
  
// Define objective function 2  
class MyObjectiveFunction2 : public QObjectiveFunction  
{  
public:  
    explicit MyObjectiveFunction2(QtOptimization::OptimizationGoal optimizationGoal = QtOptimization::OptimizationMinimizes) :  
        QObjectiveFunction(optimizationGoal) {}  
    virtual qreal evaluateOnIndividual(const QIndividual *individual) const  
    {  
        qreal x = individual->realVariableValue(0);  
        return (x-2)*(x-2);  
    }  
};  
  
QNsga2 nsga2;  
MyObjectiveFunction1 *f1 = new MyObjectiveFunction1;  
f1->setOptimizationGoal(QtOptimization::OptimizationMinimizes);  
MyObjectiveFunction2 *f2 = new MyObjectiveFunction2;  
f2->setOptimizationGoal(QtOptimization::OptimizationMinimizes);  
nsga2.setObjectiveFunctions(QList<QObjectiveFunction *>() << f1 << f2);  
  
nsga2.setSelectionOperator(new QTournamentSelectionOperator);  
nsga2.setCrossoverOperator(new QSbxCrossoverOperator(0.9, 5.0));  
nsga2.setMutationOperator(new QPolynomialMutationOperator(0.5, 10.0));  
nsga2.createRandomPopulation(48);  
  
// Improve population by 250 generations  
for (int i = 0; i < 250; ++i) {  
    nsga2.appendNewPopulation();  
    nsga2.reducePopulation(48);  
}  

We're currently implementing some quality indicators for Pareto-fronts and finish integration of such features in DuSE-MT in order to support better automated architecture design and analysis.

So, interesting stuff coming ... I'd really love to see those things effectively integrated in QtCreator, KDevelop, and Umbrello. If you are willing to join the effort, fell free to try it from code.qt.io and don't hesitate to contact me if you face any trouble.

See you,