Chapter 4. How to build a Model Compiler with Jamda

Contents

Overall approach
Define your system architecture
Create new metamodel elements
Create Model Transformers
Create the configuration

Overall approach

The most important aspect of the Jamda approach to generating code from a UML input model (see Creating the UML Model) is this:

First generate new elements for the UML model, then generate code from those new elements
The new classes for each layer or tier of the generated application are added one after another to the UML model. The classes in each layer are generated from those in the previous layer, as well as from information in the original input model. The final UML model holds a representation of the whole application, as well as the original input model. The code for each class is generated from the generated UML representation of that class, not directly from the input model. Among the advantages of this approach are:

  • Defining the generated classes is much easier, as you are working with metamodel elements, rather than source code text. The transformation code is usually shorter, and its purpose is easier to understand, than when transforming directly from the input model to code.

  • Code generation is much easier, as the distance between the UML representation of each class and the code is much smaller. UML elements (classes, attributes, operations, etc) can be translated one-for-one into the equivalent Java language features. In most cases the developer can just run the standard Jamda code generator on the transformed UML model.

  • It is easier to keep the generated layers consistent with each other. Changes tend to "ripple through", rather than having to change the transformation for each layer separately.

Define your system architecture

Before starting to build your Model Compiler, you (or a system architect working with you) must define what you want it to produce. You will need to define the different layers, or tiers, in your system. You do not need to define the actual classes in each layer, as these will be generated by the Model Compiler, but you need to define the kinds of classes or interfaces in each layer. For example, for a business logic layer implemented using EJBs, you might want the following kinds:

  • Entity beans

  • Entity local interfaces

  • Entity local home interfaces

  • Value objects

For each kind of class, you will need to know the kinds of attributes and operations required. These may be defined for you by a technical specification such as the EJB specification, or they may be up to you to define as part of your system architecture. Most importantly, you will need to know how the classes, attributes and operations are related to the classes, attributes and operations in the input model.

System architecture is a huge subject in its own right. For J2EE system architecture, there are many resources at the Sun J2EE website.

Create new metamodel elements

For each of the kinds of classes or interfaces in the system architecture, it is best to create a new Jamda metamodel class. The new class extends ClassType if it represents generated classes, or InterfaceType if it represents generated interfaces.

The new metamodel class should have a constructor which initialises its features from a source metamodel element, which will usually be a ClassType in the input model, or another generated ClassType or InterfaceType. The features will depend both on the kind of class it represents and the source element. For example, an Entity EJB might be generated from a class in the input model. It would contain metamodel Operations for the fixed standard methods defined by the EJB specification, which do not depend on the source element, and a pair of abstract getter and setter Operations for each property of the source class.

Create Model Transformers

You need to create one or more ModelTransformer implementations. You could have one large ModelTransformer that carries out all the transformations, or divide it up into one for each kind of class to be generated. The best way is probably in between these two extremes, with one ModelTransformer for each layer of the system. This keeps them to a manageable size, but all the related classes for one layer are generated together in one place.

Each ModelTransformer selects certain source elements in the model from which it generates new elements. The source elements may be from the original input model. or they may have been generated by another ModelTransformer. The source elements are typically selected by their stereotype, and they are usually ClassType or InterfaceType elements. The ModelTransformer creates one or more new metamodel elements from each source element. The new metamodel elements are usually of one of the specialised metamodel classes described in Create new metamodel elements.

Create the configuration

Once the Model Transformer classes are created, you need to create a model compiler configuration to run them in the appropriate sequence. The final step will usually be to generate code by running the standard CodeGenTransformer.

Jamda is most easily configured by running it under Ant, and using the Jamda Ant task. It may also be configured programatically by creating ModelTransformer objects, setting their parameters and adding them to a Transformation which may then be run by calling the run method.

The configuration will normally need to specify an XSLT stylesheet to transform the input XMI file into the XMI format requried by Jamda. This can be done with the Jamda Ant task stylesheet attribute, or the Transformation.setStylesheetFile method.