JeeWiz For Code Generation, MDD and MDA

Code Generation

Sometimes abbreviated to Codegen, this is the practice of using computer code to write computer code. It can be seen as a transformation, because to generate the code it is normal to use some form of specification as an input to be transformed.

Originally code generation was the province of compilers, where a high level computer program was turned into a low-level one that the computer understood, but these days the term encompasses far more sophisticated techniques such as the production of whole applications from specification models.

Code generation can be undertaken prior to when the code is run, making the code available in a separate step, as with a compiler. It can also be a transformation that happens on the fly, for example when code in web server pages is run through an asp or jsp scriptlet. It can be a combination of both of these, or even having several steps each one transforming to code.

The same software techniques behind code generation, from scripting to model driven development and domain specific language elements, can be used to other effects, such as text to text translation, model to model conversion, round-tripping to alter the original model, etc.

JeeWiz can be used as a very basic code generator or a highly sophisticated one, depending on your requirements.

Scripting in JeeWiz

The simplest form of supported code generation is a form of scripting. In this case a version of the code forms the template included embedded variable names. Variations of the code can be produced by substituting properties, set in a properties file or passed into the build, for the variables in the template. For example

Print filehandle "${myMessage}"

where myMessage is a property.

Jeewiz supports velocity-style commands, such as #if, #foreach and #parse. As well as velocity macros, which can be troublesome to debug, JeeWiz includes #method, helper functions, access to java language elements and several other useful features, a full list of which can be found in the Architect's Guide. JeeWiz uses a special ant build to create output from the templates, so anyone familiar with ant and velocity, two commonly used open source products, will find JeeWiz easy to pick up.

Model Driven Development - The Basics

Although it's possible to use JeeWiz just for scripting, typically a JeeWiz is used as a transformation engine. So there is a specification, perhaps an XML or UML model, that is transformed into something else. In this case the data used to vary information in the templates comes in the specification, although of course it's still possible to pass properties into the build.

So if the specification model in XML looked like:

<application switch="java">
   <page title = "My first page" />
   <page title = "My second page" >
      <section content = "This is some information I want on my second page" >
      <section content = "This is some more information for my second page" >
   </page>
</application>

JeeWiz can access the values in the model, allowing it to generate code against the application, the pages and the sections.

Model Driven Development (MDD) is a range of techniques that use models and meta-models to drive the generation of code and other output artefacts. Other things that are typically generated along with code are configuration files, documentation, test suites, build and deployment files and so on: everything for a complete application. But we're getting ahead of ourselves!

We've seen what a model looks like and no-one seems to mind about those, but when they first come across the term "meta-model" people start to go glassy-eyed. Actually these can very simple. They are a description of the items that you might find used in your model. So there might be a description of what a "page" is or a "section", and they can include special generation methods.

So a modeller puts specification in the model, and behind the scenes the architect/or meta-modeller will set up meta-model definitions and templates that are used to transform the model into the output. Meta-model definitions let us do things that can't be done using templates alone. For example, we can define a list of sections in the page meta-model, then we can write code on a page template using the #foreach directive that cycles through all the sections in the page getting them to render themselves. In fact there's a #foreach loop in the template that generated the website page you are reading at the moment, and each section is rendered in turn. JeeWiz meta models support default values and expressions, inheritance (so meta-model objects can extend other meta-model objects), overriding and polymorphism (more about that later), type conversion and unspecified property handling, so that properties put in the model that the meta-model knows nothing about, still work. There are plenty of other features too which you'll find in the Architect's Guide.

JeeWiz meta-model objects are specified in xml, which is transformed into java classes before code generation from the model begins. So we have the meta-model objects specified as java classes, and we read in the XML model. This lets JeeWiz create an object tree of java instances that corresponds to the specification. So in the case of the simple XML model we were looking at before, the top level would be an application object, this would have a List of pages, containing the two page objects, and the second of the page objects would have a List of sections containing the two section objects.

To render the output, JeeWiz walks the tree, and for each object whose type has a build instruction it uses the template (or templates) specified for that object to create output files. Object types each have a separate directory (or directories) where their templates can be placed. Even though it gives more flexibility, you don't always need a meta-model object. It's possbile to specify a class not defined as a meta-model object and as long as there's a directory for the templates, the output will still be rendered.

Model-to-Model Transforms and JeeWiz Patterns

Many simple code generators go no further than the approach I've outlined about and there's a considerable amount you can do with it, especially considering that the generated output can be input for a second pass. In that case the output of the first pass will be another model, and this technique is called model to model transformation. By running several transformations, each specific to the type of final output you want, you can slowly transform a logical, platform-independent model (PIM) to one that is tailored to the output language, the database you want to use, the operating system and so on, referred to as platform specific models (PSMs). By choosing different sets of transformations, the same input specification can be used to create different versions of the same application, designed to run in different environments.

But chaining model to model transformations isn't the best approach to solve this problem and high-quality commercial generators provide more flexible solutions. JeeWiz is no exception.

The first java object tree that is read in as specification can be modified to create a tree more appropriate for rendering the output. Trivially, we might want to change property values, for example if a field name is invalid in the language we are trying to generate, we can transform it to something else, perhaps keeping the original for use as a label. Or we might want to generate default values for properties based on other property values; if there's nothing in the specification for the page title but there's a header, we might want to fill in the title value based on the header. This sort of thing can simplify the final template rendering. We might want to sort a list so that child elements are rendered in a different order. We call the code for these changes patterns.

JeeWiz provides three pattern stages for the alteration of the input model. First the pre-include stage, then the extra-include stage and finally the include stage. All these are undertaken before rendering the output files and have their own separate tree-walks. By specifying a pattern in a file called IncludeSpec.vm in the directory of the page, JeeWiz will automatically apply the pattern during the appropriate tree walk. Similarly use PreIncludeSpec.vm or ExtraIncludeSpec.vm. Each of these patterns specification can call other specifications so you can write modular code.

Patterns can go much deeper than tweaking a few property values. It is possible to add objects to the tree. For example, if there is a specified entity object, which will render code for a persistent link to a database (and possibly SQL schema, configuration files, etc), we might decide we'd like a suite of pages available to the system administrator to maintain the data. We have already written lots of rendering code for pages, so rather than duplicating this in the entity area it's much easier to add the relevant page objects to the tree. If we do this in say the include phase, JeeWiz will automatically recognise that the new page objects have not had their own include patterns run on them yet, and will not only add them to the tree currently being walked, it will run their pre-include and extra-include patterns on them as well. Of course these patterns might in turn create objects, and JeeWiz handles a fully recursive transformation of the tree. Timing issues may occur, when an object is required at a point where it has not yet been created, but following the guidelines in the Architect's Guide makes these cases rare and controls what might otherwise become hard to debug code. This level of complexity is usually only necessary when writing major transformations such as application generation from UML.

Model Driven Architecture (MDA)

This term is normally used to mean the specific model driven development approach specified by the Object Management Group (OMG), which has a standards based approach to code generation. It is possible to limit the use of JeeWiz generation to be MDA compliant if you feel you need to. We don't recommend it. JeeWiz does not currently support separate languages for the action semantic or model to model transform (QVT).

Scott Ambler of IBM lists ten things to think about before adopting MDA, many of the listed problems are mitigated by taking a more pragmatic approach to MDD. We suggest a low-impact trial before even getting to that stage.

Meta-Model, Pattern and Template Overriding and Polymorphism

It has already been mentioned that meta-models can be extended. So for example we could have a web-page extend a generic page, or a j2ee ebj-entity extend a generic entity. Because we want our models not to worry about platform or architecture, we would expect to find a generic page or entity in the initial specification and we could change that for the specific object using a pattern, or just by preprocessing the model. That could become awkward to maintain and we tend to use a different mechanism to vary how the meta-model objects, patterns and templates should be used depending on the platform and architecture we want: overriding.

The structure of the directories is split into levels which come together to make a stack. Each stack level can have a directory associated with each meta-class in which you can put templates and patterns. There is also an area for meta-class definitions and the pre-compiled java classes associated with them.

The techniques discussed so far could be handled using a single level, but by having multiple levels with an order of precedence we can look at varying the out depending on the architecture and platform. For example, we might have the meta-class called Entity in a generic persistence level and this is used to generate a class called Entity as normal and we put it in the persistence package. We can then have the special ejb entity, but still just called Entity, in a specific j2ee level, and the j2ee.Entity inherits from the persistence.Entity, so we get all the generic behaviour we want to keep, and override specific behaviour in the normal object oriented way.

Now when the model is read in to create the object tree and an entity instance is specified, JeeWiz looks through the stack to find the highest precedence meta-class called Entity, which will be a j2ee.Entity. If we had selected a different chain of stack levels, we might have picked a jdo representation of Entity rather than a j2ee one. So by varying the levels defined in the working stack we can tailor the meta-model to the architecture. If the levels are written with this in mind, they become plug and play, and it is possible for example to directly replace an Oracle database level with a SQLServer level, or a jboss application server level with a WebSphere level. Tailoring a build for a particular architecture then becomes just a matter of selecting the right stack elements for the build.

And it's not just meta-models that work this way. JeeWiz will check the level for the highest precedence occurrence of pattern such as IncludeSpec, and of templates. In these cases too, it's possible to choose between overriding and inheritance. By using the #parse("super") directive, it is possible to include the file of the same name in the stack parent. Breaking down patterns into multiple files, it is then possible to override and inherit exactly what is needed.

Properties, Methods and Controls

The final parts of the stack structure are an extension of the simplest. Properties and methods can be defined at all stack and object levels and can apply to a model class, a stack level or even globally. They can then be called during generation from any of the patterns or templates.

Controls are helper objects that are not necessarily part of the object tree, but can be attached to tree objects if you want. By configuring them according to circumstances, they can produce very different output for the same call. So a data type control, might be configured for say a java Float, and this might have a String method convertStringToInternalValue, which might look something like

#method (convertStringToInternalValue $inputString)
   #return ( "( ${inputString} == null) ? null : new Float(${inputString})" )
#end

This runs at generate time, but creates code into the output. If the data type control (let's call it $dtc) is held in a variable on say a field called (unimaginatively) $field, then we can use $field.dtc.convertStringToInternalValue("varname") to generate

(varname == null) ? null : new Float(varname)

into the output stream of a template. The same call $field.dtc.convertStringToInternalValue("varname") would generate very different code if the field were a String,

varname

as a String needs no conversion! This allows for much simpler looking templates and makes template maintenance simpler.

Putting it all Together

This isn't an exhaustive list of the capabilities of the JeeWiz engine, much less an exhaustive list of code generation techniques that could be applied. We hope you'll agree that JeeWiz has an extensive and very flexible list of features and you can find out more by reading the Architect's Guide.

Alternatively download JeeWiz and try it out.