UML2 and the Groovy EMF Builder

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.

UML2 model of 'Getting Started with UML2'

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)

The full source code is available in the EMFBuilder distribution.

Discussion

There are the following things to point out.

Download

The source code is available with the EMFBuilder distribution.

Credits

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