Using UML2 with Groovy

The UML2 project provides an EMF based implementation of the UML 2.x metamodel in Java. With the EMFBuilder it is possible to create and process UML2 models.

Introduction

The UML2 project provides an EMF based implementation of the UML 2.x metamodel in Java. The fact that the underlying technology is the Eclipse Modeling Framework (EMF) makes it possible to use the EMFBuilder with the UML2 metamodel.

Getting Started with UML2

The article Getting Started with UML2 by Kenn Hussey explains how to create UML2 models with the Eclipse editor and how to create them programmatically with Java code.

The data model is shown in the following diagram.

In the following it is shown how to create (parts of) this model with the EMFBuilder. Compare the code below to the original code in the article!

We use the UMLFactory for the EMFBuilder.

def builder = new EMFBuilder(UMLFactory)

We create a Model as the root node and then we create four primitive types and store them in Groovy variables because we have to reference them later on.

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

We define an enumeration OrderStatus with three literals.

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

The following code snippet shows the definition of the class Address. All the attributes are defined as a Property. Here the primitive type stringPrimitiveType defined above is used.

        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 there is the concept of "generalization" to model inheritance relationships. The class USAddress is a subclass of Address. This is expressed by using the Generalization object.

        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)
            }
        }

An association is a relationship between two types. For each end of an association the type, the navigability, the aggregation, the name and the lower and upper bound have to be specified. The UML2 API method Type.createAssociation(). can be used to create an association and to connect the ends to the respective types.

The following code snippet creates the composite association between Supplier and PurchaseOrder (see the edge with the black diamond from from Supplier to PurchaseOrder) with the name orders.

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

The one to many association between Customer and PurchaseOrder is created with the following code snippet.

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

Finally the model is saved into a file.

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

Discussion

There are the following things to point out.

  • The code is very concise and is a direct representation of the UML2 diagram.
  • The auxiliary methods defined in the article are not needed.
  • Beauty through brevity: shorter, less verbose, more expressive !

Download

The source code is available with the EMFBuilder distribution.

Credits

Thanks to László Sütő for contributing a patch.

Remark: This post was adapted to the new blog format in November 2016.

 "Rapid Application Development with Groovy" "Writing Eclipse plugins with Groovy"