UML2 und der Groovy EMF Builder

Einführung

Das UML2-Projekt implementiert UML 2.x in EMF. Daher kann UML2 auch mit dem Groovy EMFBuilder benutzt werden.

UML2 mit Groovy

Der Artikel "Getting Started with UML2" von Kenn Hussey erklärt, wie UML2-Modelle mit Eclipse angelegt und mit Java-Code verarbeitet werden. Dieser Artikel ist eine Voraussetzung für das Verständnis dieser Seite.

Das Datenmodell wird in folgendem Klassendiagramm gezeigt.

UML2 model of 'Getting Started with UML2'

Im Folgenden werden Teile dieses Diagramms mit dem EMFBuilder erstellt. Hierbei lohnt es sich, den Code auf dieser Seite mit dem Original-Code im Artikel zu vergleichen.

Es wird die UMLFactory als Parameter für den EMFBuilder benutzt.

def builder = new EMFBuilder(UMLFactory)

Zuerst erstellen wir ein Model als oberstes Element und erzeugen vier primitive Datentypen, die in Variablen gespeichert werden, damit sie später verwendet werden können.

def epo2Model = builder.Model(name: 'epo2') {
    packagedElement {
        def intPrimitiveType = PrimitiveType(name: 'int')
        def stringPrimitiveType = PrimitiveType(name: 'String')
        def datePrimitiveType = PrimitiveType(name: 'Date')
        def skuPrimitiveType = PrimitiveType(name: 'SKU')

Wir definieren die Aufzählung OrderStatus mit drei Literalen.

        def orderStatusEnumeration = Enumeration(name: 'OrderStatus') {
            ownedLiteral {
                EnumerationLiteral(name: 'Pending')
                EnumerationLiteral(name: 'Back Order')
                EnumerationLiteral(name: 'Complete')
            }
        }

In der Klasse Address werden zwei "Properties" definiert, die beide vom Typ String sind. Hier wird der vorher definierte primitive Datentyp stringPrimitiveType verwendet.

        def addressClass = Class(name: 'Address' ,isAbstract: true) {
            ownedAttribute {
                Property(name: 'name', type: stringPrimitiveType, lower: 0, upper: 1)
                Property(name: 'country', type: stringPrimitiveType, lower: 0, upper: 1)
            }
        }

In UML2 wird die Vererbung mit der Klasse Generalization definiert. Die Klasse USAddress ist eine Unterklasse der Klasse Address, wie es in folgendem Ausschnitt zu sehen ist.

        def usAddressClass = Class(name: 'USAddress') {
            generalization {
                Generalization(general: addressClass)
            }
            ownedAttribute {
                Property(name: 'street', type: stringPrimitiveType, lower: 0, upper: 1)
                Property(name: 'city', type: stringPrimitiveType, lower: 0, upper: 1)
                Property(name: 'state', type: stringPrimitiveType, lower: 0, upper: 1)
                Property(name: 'zip', type: intPrimitiveType, lower: 0, upper: 1)
            }
        }

Eine Assoziation ist eine Beziehung zwischen zwei Klassen. Für jedes Ende der Assoziation muss der Typ ("type"), die Navigierbarkeit ("navigability"), die Aggregation ("aggregation"), der Name und die Kardinalität (untere und obere) angegeben werden. Die UML2-API-Methode Type.createAssociation(). kann eine Assoziation erstellen und mit zwei Typen verbinden.

Im folgenden Codeausschnitt wird die Assoziation zwischen Supplier und PurchaseOrder mit dem Namen orders definiert. Dieses entspricht der Kante mit der schwarzen Raute von Supplier zu PurchaseOrder im Diagramm).

        supplierClass.createAssociation(
                                          true,  AggregationKind.COMPOSITE_LITERAL,
                                          "orders",   0, LiteralUnlimitedNatural.UNLIMITED,
                      purchaseOrderClass, false, AggregationKind.NONE_LITERAL,
                                          "",         1, 1)

Die Eins-zu-N-Assoziation zwischen Customer and PurchaseOrder wird beispielsweise folgendermaßen definiert.

        customerClass.createAssociation(
                                          true, AggregationKind.NONE_LITERAL,
                                          "orders",   0, LiteralUnlimitedNatural.UNLIMITED,
                      purchaseOrderClass, true, AggregationKind.NONE_LITERAL,
                                          "customer", 1, 1)

Schließlich wird das Model in einer Datei gespeichert.

UML2Utilities.save('data/epo2.uml', epo2Model)

Diskussion

Folgendes ist bemerkenswert:

Download

Der Source Code ist im EMFBuilder enthalten.

Danksagungen

Vielen Dank an László Sütő für den Patch.