iQgen Documentation

innoQ Deutschland GmbH, Ratingen, Germany

innoQ Schweiz GmbH, Cham, Switzerland

This documentation is part of innoQ's iQgen product suite and licensed under the terms of the accompanying license agreement.

iQgen is accompanied by, or makes use of third party software. The corresponding license agreements can be found here.

Januar 2007

Revision History
Revision 3.0.2Januar 2007innoQ
Revision 2.1March 2006innoQ
Revision 2.0April 2004innoQ

Abstract

This is the product documentation for iQgen, innoQ's model driven software generator.


Table of Contents

Preface
Support, Community, and Feedback
Release Notes
Version 3.0
Version 2.1
Version 2.0
1. Installation
System Requirements
Supported Operating Systems
Java Development Kit
CASE Tools
Installing using the Windows Installer
Installing the zip Archive
Installing the tar.gz Archive
Installing iQgen for Ant
Installing iQgen for Eclipse
2. User Guide
Introduction
Tutorial 1 Overview
UML Profile
Model
Tutorial Files
Generating Artifacts with the GUI
Writing iQgen Templates
Using XMI
JSP Syntax
How JSP are used in iQgen
Extending Generated Code
Using your own Tag Libraries
When to use Tag Libraries
Deploying Tag Libraries in iQgen
Using your own Tag Libraries in Templates
The iQgen Sample Tag Library
Transformation Properties
Setting Transformation Properties
Retrieving Transformation Properties
Manipulating Transformation Properties
Transformation Properties in Action
Model Validation
UML Profile
Model
Templates
Dynamic Classloading
UML Profile
Model
Templates
Generation
Activity diagrams
UML Profile
Model
3. Design Considerations
Does generating Code make Sense?
Good and Bad Code Generation
Generic vs. Generative Solutions
UML Profile Design
Forward Engineering & the Development Process
Embedding Code Generation in your Development Cycle
Generating Code in regular automated Builds
4. Reference
User Interface
Main Screen
Generation
Root Path
Menu Overview
Properties
Logging
Command Line Options
Ant Integration
Eclipse Integration
Using the iQgen Plug-In
iQgen Console
Planned Features
The MetaModel
iQgen TagLib
IfTag
ForEachTag
ImportTag
PropertyTag
UserCodeTag
JSPFilenameTag
Tool Interoperability
Test Procedure
Static UML
Dynamic UML
5. Helpful external Resources
Glossary

List of Figures

1.1. Installed iQgen Eclipse plug-in
2.1. Tutorial 1 packages
2.2. Tutorial 1 dependencies class diagram
2.3. Main window with step-by-step marks
2.4. Invalid model
2.5. Valid model
2.6. Simple message board model
2.7. Login flow
4.1. Main window with loaded objects
4.2. Invalid entry (directory does not exist)
4.3. Valid entry (existing directory)
4.4. JSP-Engine properties
4.5. iQgen project editor
4.6. iQgen console
4.7. UML 1.3 - Core Package - Backbone
4.8. UML 1.3 - Core Package - Classifiers
4.9. Novosoft's UML Core Package

List of Tables

2.1. Files in Tutorial 1
2.2. Some of the implicit objects available in a JSP template
2.3. Methods for accessing Transformation Properties
2.4. Methods for manipulating Transformation Properties
2.5. Files for the Model Validation example
4.1. File menu
4.2. View menu
4.3. Run menu
4.4. Options menu
4.5. Help menu
4.6. XMI versions exported by different CASE tools
4.7. Tool specific support of associations
4.8. Supported interface and class inheritance
4.9. Supported stereotypes and tagged values
4.10. Supported attributes and operations properties
4.11. Supported package/class/interface dependencies
4.12. Tool specific support of associations

Preface

First of all: Thank you for using iQgen, innoQ's model driven software generator.

We have tried to make this manual as comprehensive, understandable and useful as possible. Unfortunately errors aren't completely avoidable. Should you find one - please let us know.

After you have installed iQgen, the user guide will help you with your first steps. To provide you with some hands-on experience, many sections of this guide will refer to samples you installed as part of the iQgen distribution. The most important of these samples is Tutorial_1, which will be referred to throughout the documentation. Once you have mastered Tutorial_1 the reference at the end of this document will be a helpful companion while working with iQgen.

Enjoy.

Support, Community, and Feedback

We are very interested in your experiences with iQgen. Therefore we invite you to let us know about your suggestions, problems or praise via email. Just write to

Please remember to include the following information in your email:

  • Operating System

  • JDK manufacturer and version

  • iQgen version

  • CASE tool manufacturer and version, XMI exporter

  • XMI version

Release Notes

Version 3.0

The following features are new in iQgen 3.0:

Plugins for iQgen

The Plugins for iQgen introduce a new infrastructure to support more and different types of models. Previous versions officially only supported UML 1.X compliant models which were stored in XMI files. As the core of iQgen now handles any type of models, other model sources can be easily processed. With the right plugin iQgen can generate from any source of information, whether this is an UML model or not. The following list contains some examples of already implemented extensions based on iQgen 3.0:

  • Ecore (www.eclipse.org/emf)

  • Mapping between Ecore and UML 1.X

  • Instances of Ecore models (with Dynamic EMF)

  • UML2 (www.eclipse.org/uml2)

  • Mapping between UML2 and UML 1.X

  • JAXB (Java XML Data Binding)

  • WSDL (Web-Service Description Language)

  • XML-DOM (XML Document Object Model)

  • Databases (both schema and content)

To give you the opportunity to evaluate these capabilities please download the free "plugin pack" (iQgen-plugins-1.0.zip) with some plugins for our webpage. It contains these plugins:

  • ecore

  • ecore library sample (the library sample from Ecore)

  • uml2

  • xml (for XML-DOM)

For installation instructions please read the included readme.txt.

Version 2.1

The following features are new in iQgen 2.1:

Support for Eclipse 3.0

The iQgen Eclipse integration has been updated to work with Eclipse 3, the latest version of the leading Open integrated development environment.

Smart Generation

Previous versions of iQgen generated files whenever the source model changed. With Smart Generation, iQgen checks whether the file's contents would change when generating, and only updates the file when necessary. While generation is seldomly, if ever, a performance problem, some configuration management systems and almost all build tools mistakenly check only for the timestamp of input files, and performed unnecessary work. With Smart Generation, build and check-in/check-out times are thus significantly reduced in larger projects.

Configurable XMI Readers

To ease support for CASE tools and other software emitting XMI, the XMI reader associated with a particular XMI generator is configurable in an external XML file.

Mac OS X Support

iQgen 2.1 has been bundled as a Mac OS X application, supporting simple drag & drop installation and the native Mac OS X look & feel (i.e. the menu bar where a Mac user would expect it to be, quit, preferences and about menus in the right places, storage of user preferences in the appropriate location etc.).

License Manager

The integrated license manager facilitates management of iQgen demo and unlimited licenses.

Version 2.0

The following features are new in iQgen 2.0:

Eclipse Plugin

In addition to the stand-alone user interface, iQgen is now fully integrated with the Eclipse platform. The iQgen Eclipse plugin enables you to edit templates, start the generation process, and edit the resulting artifacts - all without leaving the IDE. Combined with an Eclipse-integrated modeling tool such as TogetherEC, all of your MDA toolset can be combined in a single environment.

Enhanced user interface

We have made numerous improvements to the user interface, including the ability to view stereotypes and tagged values.

Based on customer feedback, we have created hooks that allow iQgen users to validate their UML models, e.g. to check compliance to the UML profile being used. As this is a programmatic interface, there is virtually no limit to what can be checked. Validation errors can be defined to emit warnings, errors or fatal errors (the last of which will terminate the code generation process).

Properties to control transformation settings

Not all information should be stored in the UML model; with advanced template sets, there is often a need for an easy way to provide parameters. Transformation settings are an easy-to-use solution to this problem.

Improved logging when executing from the command line or as an Ant task

Log filters that have been available in the UI only in previous versions of iQgen are now usable from both the command line and from Ant scripts that use the iQgen Ant task.

Updated and enhanced documentation

We have restructured and extended the documentation for iQgen, as well as moved to a documentation format. The documentation is now available as a Windows Help file, in a Webhelp format featuring a Java applet for navigation, and in plain HTML.

Chapter 1. Installation

Before you install iQgen please take some time and verify that your system meets the system requirements laid out in the next section. Then you should decide which distribution format best fits your needs. iQgen comes in three different flavors:

  • as a ZIP archive, extractable with WinZip™ and other, similar tools

  • as a GZIP-compressed tar archive (for Unix™ or Cygwin™ users)

  • as a self-extracting installation program for Windows operating systems

  • As a Mac OS X 10.x application compressed in .tar.gz format.

The Windows installer is the easiest way to get iQgen up and running if you are on a Windows platform. If you plan to use iQgen on both Windows and Unix boxes, you may want to use the same .zip or .tar.gz archive for both installations. The Mac OS X distribution is the easiest way to get up and running on this fine platform.

System Requirements

Like any other tool iQgen requires a certain execution environment. The following sections list these requirements.

Supported Operating Systems

You can install iQgen on any machine capable of running a Java Development Kit (JDK) version 1.3 or higher. iQgen has been successfully tested on the following platforms:

  • Microsoft Windows NT 4.0 with Service Pack 5

  • Microsoft Windows 2000 Professional

  • Microsoft Windows XP

  • SuSE Linux 7.1, 8.0, 9.0

  • Apple Mac OS X 10.3, 10.4

  • Eclipse 3.2

Other operating systems that a JDK is available for (e.g. Solaris or AIX) will probably work as well; please note that innoQ only supports the operating systems mentioned above.

Java Development Kit

Before you install iQgen, you should have a working Java Development Kit (JDK) installation on your system.

Important

Note that the Java Runtime Environment (JRE) is not sufficient, because iQgen needs to compile Java source code it generates, even if you do not use Java as your programming language.

You can get the JDK from Sun's web site at http://www.java.com/.

CASE Tools

iQgen uses XMI as its input format. Specifically, iQgen has been tested against the XMI exported by the following CASE Tools:

If you do not have any of these available, we suggest that you either request an evaluation license of one of the commercial tools or download the free ArgoUML.

Installing using the Windows Installer

Start the installation process by double-clicking on the .exe file in Explorer and follow the instructions.

Installing the zip Archive

Extract all files from the .zip file to a directory of your choice, e.g. c:\Program Files\iQgen. You can use any location you like, just make sure that you remember to replace your installation root directory wherever we refer to it throughout the documentation. In the root directory, you will find scripts called iqgen.bat (for Windows platforms) and iqgen.sh (for Unix or Cygwin installations). The file iqgen.bat assumes, that Java was correctly installed and java.exe is part of the %PATH% variable. For iqgen.sh, modify it and set JAVA_HOME to the appropriate value, e.g. c:\jdk1.3.1.

Installing the tar.gz Archive

First decide where you want to install iQgen. We assume that you choose /usr/local, but you can use anything you like - just make sure that you remember to replace your installation root directory wherever we refer to it throughout the documentation. Change to the directory you just created and extract the archive's contents using the following command:

gzip -d -c iQgen-x.x.tar.gz | tar xvf

This will create a directory called iQgen under the current directory. In the root directory, you will find a script called iqgen.sh. Edit this file and set JAVA_HOME to the appropriate value, e.g. /usr/local/jdk1.3.1

Installing iQgen for Ant

To install iQgen for Ant, just execute the local_ant_install.xml file that is located in your iQgen home directory. It will copy all necessary files to your Ant directory. Please note that for this to work, the environment variable ANT_HOME must be set.

Installing iQgen for Eclipse

The Eclipse plug-in is not yet a standard component of iQgen. Before installing, please download it from our website.

Then simply unpack the .zip archive into your Eclipse/plugins directory. The unpacked directory structure is shown in the figure below.

Figure 1.1. Installed iQgen Eclipse plug-in

Installed iQgen Eclipse plug-in

Chapter 2. User Guide

Introduction

This guide is designed to help you getting started with iQgen, innoQ's model driven software generator. If you have no idea what Model Driven Architecture is, we suggest you spend some time to read up on the topic on the Object Management Group's (OMG) website: http://www.omg.org/mda/ For the impatient developer, here is a short summary taken from the OMG's site:

The MDA is a new way of writing specifications and developing applications, based on a platform-independent model (PIM). A complete MDA specification consists of a definitive platform-independent base UML model, plus one or more platform-specific models (PSM) and interface definition sets, each describing how the base model is implemented on a different middleware platform. A complete MDA application consists of a definitive PIM, plus one or more PSMs and complete implementations, one on each platform that the application developer decides to support.

MDA development focuses first on the functionality and behavior of a distributed application or system, undistorted by idiosyncrasies of the technology or technologies in which it will be implemented. MDA divorces implementation details from business functions. Thus, it is not necessary to repeat the process of modeling an application or system's functionality and behavior each time a new technology (e.g., XML/SOAP) comes along. Other architectures are generally tied to a particular technology. With MDA, functionality and behavior are modeled once and only once. Mapping from a PIM through a PSM to the supported MDA platforms will be implemented by tools, easing the task of supporting new or different technologies.

To put this into context: Actually MDA is a successor to the model driven generative approach which has been around since the early nineties. In the mid-nineties, this generative approach failed partly due to the fact that code generators often had problems re-generating and merging artifacts. But that was only one reason for the artifacts of the development process to become inconsistent. The divergence of artifacts was a big problem, and still is. It has to be addressed carefully with an appropriate process.

The novelty of MDA, which makes it so powerful and promising, is the fact that there are well defined middleware standards like J2EE and CORBA. They and MDA together enable us to separate modeling concerns on the conceptual level rather than on a project or enterprise level. This means that there is a new chance for all of us to achieve long term technology independence and protection of investments. As mentioned by the OMG, tools are needed to support this process.

iQgen is one of these tools. With iQgen you can map your platform-independent model (PIM) to a platform-specific model, i.e. a model specific to a platform like .NET or J2EE.

Not surprisingly, you need to create the PIM somehow. The easiest way to do this is to use a CASE tool. Just create a model with one of the supported case tools and export it as an XMI file.

Your platform independent model is transformed to a platform specific model by means of a transformation, which is defined as a set of code generation templates.

In iQgen, there is no explicit PSM other than the code of your generated system. Conceptually, you can think of iQgen creating the PSM in a transient form. We have found this approach to work extremely well, although we consider adding model-to-model transformation to a future version of iQgen.

Once you have a PIM and at least one set of templates, you can simply hit iQgen's generate button and your application will be generated for a given platform. How well this works depends on the quality of both the PIM and the templates.

In order to successfully work with iQgen you need to understand how to specify your transformation, i.e. how to write templates. But before we delve into template creation, you should first get a better understanding of how code generation with iQgen works. This will be covered in the next section of this tutorial.

Tutorial 1 Overview

To get some hands-on experience with iQgen we recommend to run the tutorial that comes with the iQgen distribution. You will find the templates in the directory samples/getting_started/tutorial_1/templates and the XML models in XMI format in directory samples/getting_started/tutorial_1/model.

UML Profile

The UML profile for Tutorial 1 is extremely simple - essentially, it doesn't use any stereotypes or tagged values at all.

Model

Tutorial 1 uses the model depicted in the figure below. It will not result in a complete application, but in the end you will have source code which can be compiled and you will have obtained a deeper knowledge of how to develop templates.

Figure 2.1. Tutorial 1 packages

Tutorial 1 packages

Figure 2.2. Tutorial 1 dependencies class diagram

Tutorial 1 dependencies class diagram

Tutorial Files

To give you an overview of the templates in Tutorial 1, here's an overview table with some short comments.

Table 2.1. Files in Tutorial 1

DirectoryFileComment
./build.xmlAnt script for generation
modelTutorial_1.xmlXMI v1.0 model file
modelTutorial_1.mdlRational Rose model file
templatesmain.jspModel element to template mapping
templatesinterface.jspSimple example that demonstrates how to generate a Java interface
templatesclass.jspMore complex example that generates Java class files. Uses other templates like associations, attributes, and operations
templatesattributes.jspUsed by class.jsp. Generates attribute declarations, getter and setter methods.
templatesoperations.jspUsed by class.jsp. Generates methods.
templatesassociations.jspUsed by class.jsp
templatesbuild.jspPostProcessTemplates example
templatescopyright.jspCopyright text
templatesdrop_and_create.jspSimple SQL script
templatesparams.jspUtility JSP that is included by other templates.
templatesutilities.jspUtility JSP that is included by other templates.

Generating Artifacts with the GUI

In order to generate the files for the Tutorial 1 model, simply start iQgen and select the tutorial's model file. Then set both the target and template directory and start the generation. You will find the generated file in the output directory you chose. The next paragraph will guide you through the process step-by-step.

When you start iQgen you should see the screen below. This is the main screen. All settings necessary for generation can be found right there. The numbers (1-10) in the figure correspond to the 10 simple steps necessary for code generation.

Figure 2.3. Main window with step-by-step marks

Main window with step-by-step marks

Just follow these steps and you will generate some sample code (for this example we suggest that you have installed iQgen under c:\iQgen):

  1. Project Root Path. Enter your project root path here: C:\iQgen\samples\getting_started\tutorial_1

  2. Source Model File. Here you need to set the location of the model file: C:\iQgen\samples\getting_started\tutorial_1\model\tutorial_1.xml

  3. Target Generation Path. This is where the generated files can be found after successful generation: C:\iQgen\samples\getting_started\tutorial_1\out

  4. Template Path. Directory containing the templates: C:\iQgen\samples\getting_started\tutorial_1\templates

  5. Master Template. Select your master template: main.jsp

  6. Load Model. Now that all paths and files are set, you have to load model by clicking the toolbar button.

  7. Generate. Start the generation by clicking the toolbar button.

  8. Output. The output window should now contain the lines shown in the screen shot.

    Note

    Technically the generation is now complete. The following two steps are entirely optional.

  9. Open Generated File. Click on the tab Generated Files and double-click on one of the files. It will be opened in the editor.

  10. New Transformation. Finally you can create a new transformation via File, New Transformation. Just specify a location and a file name (e.g. tutorial_1).

Done. You have successfully created your first set of artifacts from the provided model file.

Tip

The GUI is not the only way you can use iQgen. You may also generate artifacts from the command line or from an Ant build file.

Writing iQgen Templates

Using XMI

XMI, like many other standards, is unfortunately not a guarantee for interoperability. Different CASE tools export to XMI differently, and this can lead to interoperability problems. iQgen tries to minimize these by streamlining the differences by means of the MetaModelFacade API. Nevertheless, iQgen allows you to access everything that your CASE tool has exported. If you need to make sure that you can change CASE tools in the future, we strongly encourage you to use the MetaModelFacade as much as possible.

JSP Syntax

iQgen uses an embedded Java Server Pages (JSP) 1.1 engine to execute your templates. If you are familiar with JSP syntax, developing templates with iQgen should be a piece of cake. However, as not everybody can be fluent in JSP, we will give a short introduction.

A JSP's content is a mixture of literals, directives, declarations, scriptlets, and actions. Sun's JSP syntax card gives an excellent overview of which syntactic elements are legal in a JSP. The following paragraphs cover the most important of these elements. If you are familiar with JSP, you may skip this section and continue with how JSP are used in iQgen.

Declarations

To understand the concept of JSP a little bit better it often helps to know that each JSP is compiled into a Java class. Like any other class this class has methods and fields. Not surprisingly you can also declare methods and fields in a JSP. This is done like this:

<%! declaration; [ declaration; ]+ ... %>

I.e. if you wanted to declare a method getDate() which returns the current date, you could write:

<%! public java.util.Date getDate() { return new java.util.Date(); } %>

You might have noticed that instead of simply writing Date, we used the fully qualified classname java.util.Date. Of course this is very tedious, if you have to use classnames like com.great.company.with.a.very.long.name.util.MasterUtility. No one likes to write classnames like this. Therefore, each JSP can import packages. The mechanism is exactly the same as in Java - just the syntax is different:

<%@ page import="{package.class|package.*}, ... " %>

Example:

<%@ page import="java.util.*,java.net.URL" %>

Ideally you place such a page directive at the top of your page. In addition to the packages you want to import, the page directive lets you specify a class you want to extend. As mentioned before, a JSP will be compiled into a special Java class. This class may inherit some of its behavior from a superclass. To specify this superclass, you may place a page directive with an extends attribute in your page:

<%@ page extends="package.class" %>

Example:

<%@ page extends="com.innoq.generator.jsp.JspBase" %>

You probably have guessed that you cannot simply subclass any class. Contrary to ordinary JSP engines, iQgen restricts you to extend com.innoq.generator.jsp.JspBase or any of its subclasses. This ensures that certain functionalities expected from iQgen are always available in your templates. If you do not specify a class you want to extend, iQgen will automatically use com.innoq.generator.jsp.JspBase as default class.

Of course declaring methods and inheriting functionality does not get us very far. At least it does not generate any output. Therefore we want to explore means of generating...

Literals

Everything you write in a JSP that isn't marked with special tags (usually starting with <% and ending with %>) will be copied to the output of your template literally. And everything means everything - in particular this rule applies also to whitespace such as tabs, spaces, and newlines.

Expressions

Expressions provide you with a way of inserting the value of objects or primitives ( int, float, boolean, ...) into the output. In the case of primitives the value is printed, in the case of an object either null is printed or the result of the toString() method. The syntax is as follows:

<%= any kind of Java expression %>

Example:

<%= new java.util.Date() %>

This prints the current date. Of course you can also use other Java expression such as the conditional ? : operator, a method invocation, or any combination of valid expressions.

<%= i>100 ? "i is greater  than 100" : "i is not greater than 100" %>
<%=someObject.someMethod() %>

Scriptlets

With the means we introduced so far, we cannot use control structures like loops or embed a great deal of logic in our templates - or at least not in a reasonable way. Scriptlets offer you a way to easily embed any valid Java code, you could otherwise write in a method, in your template. Note that you cannot declare methods here.

<% code fragment of one or more lines %>

And this is how you can write a loop with a scriptlet:

<%
// this is a comment in Java code
// first scriptlet
for (int i=0; i<100; i++) { %>
   Number: <%=i%>
<%
// second scriptlet
} %>                    

In the first scriptlet the block that shall be executed 100 times is opened with a curly brace; in the second scriptlet it is closed again. In between we placed a literal ( Number:) and an expression ( <%=i>). They will both be evaluated, i.e. printed, 100 times.

Please note that this might look very practical and simple, but is actually a maintenance nightmare. Often taglibs (we will talk about them later) do a much better job at encapsulating control structures like conditional execution ( if) or repeated execution ( for, while).

Including Files statically

JSP are capable of including other files, which are statically compiled into your template and executed as if they have always been part of your template. Syntax:

<%@ include file="relativeURL" %>

This is often very useful, if you have a lengthy import section in all your JSP or a copyright notice that always stays the same. Simply include it, where you need it. Example:

<%@ include file="copyright.txt" %>
<%@ include file="imports.jsp" %>                    

Please note that you can include files containing literals as well as scriptlets or any other element of a valid JSP.

Implicit Objects

Of course JSP aren't executed in a vacuum. To access your environment you can use a number of implicitly declared variables. Some of them are listed in the table below.

Table 2.2. Some of the implicit objects available in a JSP template

NameTypeComment
requestjavax.servlet.ServletRequestThe request from the generator.
responsejavax.servlet.ServletResponseThe response to the generator. Not typically used by iQgen authors.
pageContextjavax.servlet.jsp.PageContextYou can store objects in this context.
outjavax.servlet.jsp.JspWriterThe Writer the output is written with.

Taglibs

As mentioned above, taglibs provide a much cleaner way of encapsulating certain tasks or logic. In order to use a taglib, you first have to register it with the page you want to use it in. This can be done with the taglib directive. Syntax:

<%@ taglib uri="taglibURI" prefix="prefix" %>

iQgen comes with a default taglib with the URI iqgen. To use a custom taglib you need to place it in the taglibs directory. The uri refers to the name of the taglib Jar file without the .jar suffix. Once you have registered the taglib, you can use it with the prefix you chose in the taglib directive:

<tagPrefix:tagName attribute="value"+... />
<tagPrefix:tagName attribute="value"+... >
...
</tagPrefix:tagName>                    

iQgen comes with a pre-built taglib, which we will be mentioned again later.

Further Resources

Since JSP aren't brand new anymore there are plenty of books and online tutorials around.

How JSP are used in iQgen

iQgen uses JSP for two purposes:

  • the mapping of model elements to templates

  • the templates themselves.

From Model Element to Template

As you know, a model consists of different model elements such as classes, interfaces, associations, diagrams and so forth. Usually a single model element cannot be mapped one to one to a generated file. Instead often a single model element leads to the generation of multiple files, e.g. a SQL script, a configuration file, a deployment descriptor and a couple of classes. Therefore you need to specify which files should be generated for a given model element. To allow you to specify this in a very flexible and powerful way, this is done with a special JSP - the file main.jsp - a.k.a. the master template.

There are three things you need to do, to write your own main.jsp:

  • Extend the class com.innoq.generator.jsp.JspMain

  • Implement the method public String[] getTemplates(MBase)

  • Implement the method public String getName()

So the most basic main.jsp looks like this:

<%@ page extends="com.innoq.generator.jsp.JspMain"
         import="ru.novosoft.uml.MBase" %>
<%!
/**
 * For performance reasons this array is declared as static
 * final and can be reused for every invocation of getTemplates.
 */
private static final String[] TEMPLATE = {"template.jsp"};

/**
 * Returns the names of the templates to execute for a specific
 * model element.
 *
 * @param element The model element to return the template names for
 * @return Array of template names for a element
 */
public String[] getTemplates(MBase element) {
   return TEMPLATE;
}

/**
 * Name of this modelelement-template mapping.
 */
public String getName() {
   return "My first main.jsp";
}
%>                        

This main.jsp would return the name of the template template.jsp for every model element. Of course this only makes sense in the most simple case. You cannot to generate a SQL script and a Java class file for a persistent object with a single template. Our next example shows a slightly more complex, but a lot more realistic mapping:

<%@ page extends="com.innoq.generator.jsp.JspMain"
         import="ru.novosoft.uml.MBase" %>
<%!
private static final String[] PERSISTENT = {"class.jsp", "drop_and_create.jsp"};
private static final String[] INTERFACE = {"interface.jsp"};
private static final String[] DEFAULT = {"class.jsp"};

public String[] getTemplates(MBase element) {
   String s = getMetaModel().getStereotype(element);
   String name = getMetaModel().getName(element);
   if ("Persistent".equals(s)) {
      return PERSISTENT;
   } else if (getMetaModel().isInterface(element)) {
      return INTERFACE;
   } else {
      return DEFAULT;
   }
}

public String getName() {
   return "My second main.jsp";
}
%>                        

Instead of always returning the same template name for every model element, we return PERSISTENT for all model elements marked with the stereotype Persistent, INTERFACE for all interfaces and DEFAULT for all other madel elements. This allows us to generate SQL scripts with the template drop_and_create.jsp and class files with class.jsp for all persistent madel elements. All other elements lead to the generation to either an interface or a class file.

Let's look how this is done in detail. In every iQgen JSP you can obtain access to the model by invoking the method getMetaModel(). This will return an object of the type com.innoq.generator.metamodel.IMetaModelFacade, which can help you inspecting the current modelelement. The three methods we use in this example are getStereotype(MBase), getName(MBase), and isInterface(MBase). Additionally the metamodel offers many more methods to obtain detailed information about the current element. All methods are covered in the API reference section.

So far we can invoke templates for and with specific model elements. Often some templates need only be invoked once per model and even without a specific model element. Such cases can be covered with the method public String[] getPostprocessTemplates(). Just overwrite this method in your main.jsp to provide the names of all templates that should be executed after all model element-specific templates have been executed:

<%@ page extends="com.innoq.generator.jsp.JspMain"
         import="ru.novosoft.uml.MBase" %>
<%! [...]
private static final String[] POST = {"build.jsp"};
public String[] getPostprocessTemplates() {
   return POST;
}
%>                        

Our example always returns the name of the template build.jsp which generates an XML file that can be used as an Ant build script. Another useful application of this feature is a template for deployment descriptors.

There are several hook methods you can overwrite to control your generation process. The following sequence diagram should help you to get an overview about the calling order. MyJspMain means your JspMain specialization. The writeToFile method should be used very carefully and at the end of this method you must call super.writeToFile(filename, inoutstream).

Figure 1: JspMain Sequence

For a complete description of JspMain 's API, take a look at the API reference section page.

JSP in Templates

The second use for JSP in iQgen is to write the actual templates.

Probably the most important methods already defined in iQgen templates are getElement() and getMetaModel(). getElement() allows you to access the model element this template was invoked for. getMetaModel() grants you access to the model - just like in main.jsp. Additionally there are some other methods already defined, mainly dealing with how to compute the name for the file to generate and other path related tasks.

As an example we will take a look at a template for generating Java interfaces.

<%@ page import="ru.novosoft.uml.MBase,java.util.Collection,java.util.Iterator"
         extends="com.innoq.generator.jsp.JspBase" %>
<%@ taglib uri="iqgen" prefix="iqgen" %>
<%! private String getClassname() {
   return getMetaModel().getName(getElement());
}

private String getExtendsString() {
   Collection superclasses = getMetaModel().getAllSuperclasses(getElement());
   if  (superclasses.isEmpty())
      return "";
   StringBuffer sb = new StringBuffer(" extends ");
   for (Iterator i=superclasses.iterator(); i.hasNext();) {
      sb.append(getMetaModel().getName((MBase)i.next()));
      if (i.hasNext())
         sb.append(", ");
   }
   return sb.toString();
}

public String getPrefix(char pSeparator, MBase m) {
   return  "com"+pSeparator+"innoq"+pSeparator+"tutorial_1"+pSeparator;
}
%>
package <%=getPath()%>;
   <iqgen:import prefix="<%=getPrefix()%>" collectiontype="java.util.List"/>
   /**
    * Interface  <%=getClassname()%>
    */
   public interface <%=getClassname()%><%=getExtendsString()%> {
      [...]
   }                        

This excerpt from the complete template generates the package statement, import statements, and the interface declaration complete with extend clause. In the first part we register the taglib iqgen and declare three methods. Let's look at the first of these three methods.

getClassname() is a simple helper method that returns the name of the interface. To obtain the model element this template is executed for we simply call the getElement() method. This method is automatically declared in every template. Using the metamodel, we find out the name of the particular element. In the case of an interface this is also the classname.

getExtendsString() works similar to getClassname(). Through the metamodel we obtain a collection of the interface's the superclasses. If this collection is empty, the method simply returns an empty string. Otherwise the names of all superclasses are appended to a StringBuffer which starts with extends.

getPrefix() is already declared in the superclass JspBase. In its default implementation it simply returns an empty string. In our example it is overwritten to return the package name. Note that the package separator is provided as a parameter. This is necessary, because this method is called for computing the filename, too. By overwriting getPrefix() in the given way we achieve that the method getPath() automatically returns the right package name and the generated file is written into the right directory, i.e. [OUTPUT_PATH]/com/innoq/tutorial_1/.

Which file the output is written to, is determined by the JspBase method getFilename(). By default this method is implemented like this:

public String getFilename() {
   return getDirectory() + File.separator
      + getPath(File.separatorChar,
      getElement())
      + File.separator + getName()
      + "." + getFileExtension();
}
	    

getPath() in turn is implemented like this:

public String getPath(char pSeparator, MBase m) {
   return getPrefix(pSeparator, m)
      + getMetaModel.getNamespaceName(m, pSeparator)
      + getPostfix(pSeparator, m);
}
                        

You can also find a complete description of JspBase's API, here in the API reference section.

So far we provided methods to easily access the classname, write the extends clause, and compute the package name. Before we write the whole interface with all its methods, it makes sense to import the classes we use in the method's signatures. Alternatively we could simply always use fully qualified classnames - but who would do this in real code? And shouldn't the quality of generated code be at least the same as the quality of handwritten code?

To gather all the import-classes we need to look at every method parameter, every superclass, every interface, every association and so forth. This is rather tedious, repetitive, and error prone work and therefore a perfect candidate for a custom tag. Custom tags allow you to encapsulate tasks like computing import tags and easily re-use their functionality. The import tag provided in the standard iQgen tag library provides the functionality to automatically generate all necessary import statements for the current class or interface. In order to keep the imports in sync with other generated files you can specify a prefix for all imports. Also, if your model contains associations with undefined multiplicity, you may specify a collectiontype that will always be included in your import statements:

<iqgen:import prefix="<%=getPrefix()%>"
   collectiontype="java.util.List"/>

Let's finish our interface-example. We still need to generate the method section. Here's how it works:

<%@ page import="ru.novosoft.uml.MBase,java.util.Collection,java.util.Iterator"
         extends="com.innoq.generator.jsp.JspBase" %>
<%@ taglib uri="iqgen" prefix="iqgen" %>
[...]
/**
 * Interface <%=getClassname()%>
 */
public interface <%=getClassname()%><%=getExtendsString()%> {
<iqgen:foreach group="<%=getMetaModel().getOperations(getElement())%>" item="method">
   <%
      String methodName = getMetaModel().getName(method);
      Object retType = getMetaModel().getReturnType(method);
      String retTypeName = getMetaModel().getReturnTypeName(method);
      String parList = getMetaModel().getParameterListAsString(method);
   %>
   /**
    * Method <%=methodName%>
    * <iqgen:foreach group="<%=getMetaModel().getParameterList(method)%>" item="parameter">
    * @param <%=getMetaModel().getName(parameter)%> <%=getMetaModel().getDocumentation(parameter)%></iqgen:foreach>
   <iqgen:if expr="<%=retType!=null%>">
    * @return <%=retTypeName%>
   </iqgen:if>
    */
   public <%=retTypeName%> <%=methodName%>(<%=parList%>) <%=getMetaModel().getExceptionListAsString(method)%>;
</iqgen:foreach>
}                        

Basically we just have to iterate over all the declared methods and print out their documentation and signature. In our example this is done using the built-in foreach tag. As attribute we define a group of elements to iterate over. This is done with the JSP expression <%=getMetaModel().getOperations(getElement())%>. Additionally we need to specify a variable in which the items of the group are to be placed during the iteration. In our case this is method. So the whole iteration looks like this:

<iqgen:foreach group="<%=getMetaModel().getOperations(getElement())%>"
   item="method">
[...]
</iqgen:foreach>                        

The rest is pretty much straight forward. First we declare a number of variables like methodName and retTypeName for easier access to the method model element. Then we print the documentation, which includes another foreach iteration over the method's parameters. Finally we print the method's signature. That's it.

Of course generating interfaces is pretty simple, because usually you don't need to add custom code.

Extending Generated Code

Generated code usually isn't perfect. Not all information is contained in model and templates, some needs to be added manually. With simple code generators the manual changes are lost during re-generation. iQgen solves this problem with usercode blocks.

During each generation the output directory is checked for files from earlier runs. If these files exist, the contents of protected sections of these files are inserted into the newly generated files. These special sections are marked as usercode blocks. Here is an example for adding custom imports to a Java file:

[...]
<%@ taglib uri="iqgen" prefix="iqgen" %>
<iqgen:usercode id="imports">
// your own imports
</iqgen:usercode>
<iqgen:import prefix="<%=getPrefix()%>"
   collectiontype="java.util.Collection"/>
[...]                    

To use the usercode tag you have to register the iqgen taglib. Once this is done, you may mark a section of the template with the tag. Make sure that you specify a unique id attribute in the opening tag. This ensures that the right piece of code is merged into this section.

In the generated code the section will look like this:

[...]
//==> Begin Protected Area imports
// your own imports
//==> End Protected Area imports
[...]                    

Never modify the //==> [...] Protected Area [...] lines!

Alternatively to the id attribute you can also set a model element as attribute element:

[...]
<%@ taglib uri="iqgen" prefix="iqgen" %>
<iqgen:usercode element="<%=getElement()%>">
// your own code for the current modelelement
</iqgen:usercode>
[...]

Note

id and element are mutually exclusive.

Using your own Tag Libraries

This chapter will show you how to use your own Tag Libraries (taglibs) with iQgen. We will use a Tag Library to format date and time data as an example. iQGen supports JSP 1.1 Tag Libraries. If you want to know how to program tag libraries, please consult the JSP 1.1 specification or any JSP tutorial.

When to use Tag Libraries

Tag Libraries enable you to write simpler templates. Basically they allow you to move complicated logic from your templates into custom tags. Templates often are much easier to read, understand, and maintain, when Tag Libraries are used. They can be structured more clearly. As a consequence, you should use Tag Libraries whenever you feel that your templates are getting too complicated and unreadable.

Deploying Tag Libraries in iQgen

Basically you can deploy every JSP 1.1 Tag Library into iQgen. The library has to meet certain criteria, though: First of all, the Tag Library has to be packed into a jar file and this jar file must contain a Tag Library Descriptor (TLD). The TLD is a file that describes the tags contained in the Tag Library. It is best - but not required - to be placed in the META-INF directory for compatibility with some IDEs e.g. IntelliJ IDEA™. The JSP engine uses this file to get all the necessary information to process the Tag Library.

Now the Tag Library can be deployed. You have to copy it into a subdirectory taglibs in the home directory of your iQgen installation (e.g. C:\Programme\iQgen). If the directory does not exist, you have to create it. Now this Tag Library can be used in all iQgen templates.

If the deployed Tag Library uses any libraries (jar files), they have to be put into a subdirectory of the taglibs directory called lib.

In case you want to use the Ant interface of iQgen a special issue arises. The jar file of the Tag Library then has to be placed in a taglibs directory in the lib directory of your Ant installation. The reason for this is that iQgen searches the jars of Tag Libraries relatively to the iQgen jar file. This jar file - in the Ant mode - resides in the lib directory of Ant.

Using your own Tag Libraries in Templates

If you have completed all the steps explained in the previous paragraph, you can use your Tag Libraries in your templates. Here is some example code which shows you how to access a Tag Library:

[...]
<%@taglib uri="your_taglib" prefix="your_prefix" %>
[...]
<your_prefix:your_tag  your_attr1="a" your_attr2="b">
   In case of a body tag there can be something in here
</your_prefix:your_tag>
[...]                    
The taglib directive ( <%@taglib ... %>) makes a Tag Library available within a template. To do this the URI of the Tag Library and the prefix must be specified as attributes of the directive. The URI of a Tag Library in the taglibs directory is the filename of the jar file of the Tag Library without .jar It is used to locate the Tag Library. Now you can use the Tag Library identifying it using the prefix, you have specified (i.e. <your_prefix:your_tag ... >).

The iQgen Sample Tag Library

The iQgen Sample Tag Library is included in the iQgen distribution, you can find it in the directory samples/getting_started/taglib_tutorial in your iQgen directory.

The Java class com.innoq.generator.samples.taglibs.SampleTag implements the date and time formating feature. The following TLD is used:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"  "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<taglib>
   <tlibversion>1.0</tlibversion>
   <jspversion>1.1</jspversion>
   <shortname>iqgen-taglib-sample</shortname>
   <info>Sample which shows you how to use the taglibs</info>
   <tag>
      <name>date</name>
      <tagclass>com.innoq.generator.samples.taglibs.SampleTag</tagclass>
      <info>Formats Dates</info>
      <attribute>
         <name>time</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
      </attribute>
      <attribute>
         <name>date</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
      </attribute>
      <attribute>
         <name>format</name>
         <required>false</required>
      </attribute>
   </tag>
</taglib>
The Tag Library contains only one tag, which is called date. The attributes are time, date and format. The allowed values for the attribute format are date, time and datetime, which is the default. If none of these values is given, the default will be used.

The tutorial includes an Ant build file ( build.xml), which can be used to compile, assemble and install the Tag Library. Just have to call the target install, respectively install-for-ant in order to make this Tag Library available for the GUI or the Ant interface of iQgen.

The important parts of the build file to illustrate what is done to deploy the Tag Library are:

[...]
<target name="dist" depends="compile">
   <copy file="${basedir}/taglib.tld" todir="${classes.dir}/META-INF"/>
   <jar jarfile="${jar.file}" basedir="${classes.dir}"/>
</target>

<target name="install" depends="dist">
   <mkdir dir="${generator.dir}/taglibs"/>
   <copy file="${jar.file}" todir="${generator.dir}/taglibs"/>
</target>

<target name="install-for-ant" depends="dist">
   <mkdir dir="${ant.home}/lib/taglibs"/>
   <copy file="${jar.file}" todir="${ant.home}/lib/taglibs"/>
</target>
[...]
As you can see the taglib.tld is copied into the META-INF directory of the jar file in order to build the jar. This ensures the correct structure of the jar file. The install and install-for-ant targets then copy the jar file into the correct directory.

After having successfully installed the Tag Library there will be a taglibsample.jar in the taglibs directory of your iQgen installation. Now you can use the taglibsample Tag Library in your templates:

[...]
<%@taglib uri="taglibsample" prefix="datelib" %>
[...]
<datelib:date format="date"/>
<datelib:date time="<%=System.currentTimeMillis() + 3600000%>" format="datetime"/>
[...]                    

This will result in the following output:

09.08.2002 09.08.2002 11:06:43

Transformation Properties

Transformation Properties represent a set of properties which can be accessed from within your templates. This enables you to add some flexibility to your templates, as you can change the result of the generation without changing the templates themselves.

This text refers to a sample which is included in the iQgen installation. The templates are in the directory samples/getting_started/properties_sample/templates. It will generate a HTML report on any model. You can use for instance the model of Tutorial 1.

Setting Transformation Properties

To use Transformation Properties from the GUI just create a properties file and place it into the project directory of the transformation you want to use. When the transformation is opened this file will appear in the Transformation Properties combo box in the GUI. Just select it and the properties are available in the templates.

In order to use Transformation Properties on the command line set the -transformationProperties option.

Example:

iqgen.bat "-transform=tutorial_1 -nobackup -transformationProperties=transformation.properties"

In Ant use the transformationProperties attribute of the Generate Task.

Retrieving Transformation Properties

If Transformation Properties are set they will be loaded when generation has started. They can be accessed in the templates via methods of the iQgen JSP base class, i.e. any iQgen JSP.

Table 2.3. Methods for accessing Transformation Properties

MethodDescription
public final String getProperty(String pKey)Returns a property with the given key pKey
public final String getProperty(String pKey, String pDefault)Returns a property with the given key pKey if defined, default pDefault otherwise
public final Properties getProperties()Returns the whole set of Transformation Properties
For more detail please see the Javadoc of iQgen.

Manipulating Transformation Properties

It is also possible to add new properties to the Transformation Properties or to change the value of an existing property. The following methods can be used:

Table 2.4. Methods for manipulating Transformation Properties

MethodDescription
public final void setProperty(String pKey, String pValue)Sets a property with given key and value
public final void setProperties(Properties pProps)Replaces Transformation Properties with pProps
public final void addProperties(Properties pProps)Adds the given properties to the Transformation Properties

Transformation Properties in Action

The following example is a set of templates which generate an HTML report for a model. A Transformation Property (sort) is used to decide whether the lists of classes, attributes or methods will be sorted:

[...]
<TABLE cellpadding="3" cellspacing="3" border="1">
   <TR bgcolor="#98AEB7" align="center">
      <TD>Class Name</TD>
   </TR>
<% List list = new ArrayList(getAttributeList("CLASS_KEY")); %>
<iqgen:if expr="<%=\"true\".equals(getProperty(\"sort\"))%>">
   <% Collections.sort(list, myComparatorInstance); %>
</iqgen:if>
<iqgen:foreach group="<%=list%>" item="item" type="ru.novosoft.uml.MBase">
   <TR bgcolor="#FFFFFF" align="right">
      <TD>
         <a href="<%=getMetaModel().getPath(item)%>/<%=getMetaModel().getName(item)%>.html">
            <%=getMetaModel().getName(item)%>
         </a>
      </TD>
   </TR>
</iqgen:foreach>
</TABLE>
[...] 
To sort the lists all you need is the following property file:
 sort=true 

Model Validation

The following example demonstrates how to validate a model exported by your CASE tool. You can find the templates and the model for this example at: ../samples/getting_started/validation. The templates use the Model Validation feature and will generate an HTML report for the underlying UML model.

Here is a complete list of files of this example:

Table 2.5. Files for the Model Validation example

DirectoryFileComment
./validation.iqpProject file for this example
./build.xmlAnt Script for generation
modelvalid_model.xmiValid model XMI file
modelinvalid_model.xmiInvalid model XMI file
modelmodel.zargoArgoUML model file
templatesmain.jspModel element to template mapping, Validation
templatesreport.jspCreates the HTML output

UML Profile

The UML profile in this case is very simple. What we want to show is how to use model validation. Model validation answers the question: Does the UML model satisfy the UML profile?

The UML profile looks like this:

  • only Entity, Process and Enum are allowed stereotypes

  • every navigable association must be named with a rolename

  • a usage dependency of processes to classes shows implicitly a get method of the used class

This is very simple but it will suffice for our needs.

Model

First let us start with the invalid model. It looks as follows:

Figure 2.4. Invalid model

Invalid model

You can find the invalid model as XMI file in the folder validation/model. Please open the transformation samples/getting_started/validation/validation.iqp. When you start generation and change to the validation page you should see that the model has three validation errors:

Unknown stereotype:Class: User
Association [Document -> Version] is navigable but missing rolename.Association:
Association [Version -> Label] is navigable but missing rolename.Association:

The Unknown stereotype error is a warning, the missing rolename exceptions are errors (different images in table!). If we used a fatal error the execution would have stopped. In our example the validation violation status are arbitrarily.

The next step is that we fix the model, remove the validation violations and re-generate. The correct model looks as follows:

Figure 2.5. Valid model

Valid model

You can load the model from the XMI file valid_model.xmi. Now re-generating will not produce errors anymore!

Templates

You can find both templates main.jsp and report.jsp in the templates directory of this example. Most of the used methods are explained in further examples so we can concentrate on the validation method (see main.jsp):

[...]
private static final List STEREOTYPES = Arrays.asList(
   new String[] {"Entity", "Process", "Enum"}
);
[...]
public boolean canBeGenerated(MBase pElement) {
   return super.canBeGenerated(pElement)
      || getMetaModel().isAssociation(pElement);
}

public ValidationMessage isValid(MBase pElement) {
   String s = getMetaModel().getStereotype(pElement);
   // valid stereotypes
   if (getMetaModel().isClass(pElement) && !STEREOTYPES.contains(s)) {
      return new ValidationMessage(ValidationMessage.WARN, "Unknown stereotype: " + s);
   }
   // navigable associations do have a rolename?
   if (getMetaModel().isAssociation(pElement)) {
      for (Iterator it = ((MAssociation)pElement).getConnections().iterator(); it.hasNext(); ) {
         MAssociationEnd lAssocEnd = (MAssociationEnd)getMetaModel().getOppositeEnd((MBase)it.next());
         if (getMetaModel().isNavigable(lAssocEnd)
               && getMetaModel().getName(lAssocEnd).length() == 0) {
            StringBuffer sb = new StringBuffer();
            sb.append("Association [");
            sb.append(getMetaModel().getTypeName(lAssocEnd.getOppositeEnd()));
            sb.append(" -> ");
            sb.append(getMetaModel().getTypeName(lAssocEnd));
            sb.append("] is navigable but lacks a rolename.");
            return new ValidationMessage(ValidationMessage.ERROR, sb.toString());
         }
      }
   }
   return new ValidationMessage(ValidationMessage.OK, "No error found!");
}
[...]                

The model validation happens programmatically. For validation purpose you can use the hook method isValid. This method is called for every model element that is to be processed during generation. You can control which model element leads to the generation of an artifact by overwriting the method canBeGenerated. By default only classes and interfaces are generated. In our example we have added associations, because the UML profile demands a validation of associations, too. Our intention is to check navigable associations and their rolenames.

In our custom isValid method we check whether all classes have a valid stereotype - if not we return a ValidationMessage of type ValidationMessage.WARN. Then we check whether all navigable associations have rolenames.

To do this we check, if the element is an association, then we take a look at the association's ends. Every association consists of two association ends which you can get by calling the method getConnections. Finally we check the UML profile constraint ("Association is navigable and has a rolename?!?"). If this constraint is violated we return a ValidationMessage of type ValidationMessage.ERROR.

If the element is no association in the first place, there is nothing to test form, so we simply return a ValidationMessage of type ValidationMessage.OK.

Tip

In a real world application the model validation would be more complex. Therefore we recommend to handle it in a separate class. Our experience is that it is also an incremental process to make your model validation more and more detailed. In a way, this is comparable with unit testing your model.

Dynamic Classloading

Dynamic classloading allows you to change certain classes while the iQgen GUI is running. Maybe you like Java helper classes do some work for your generation progress. Typically these classes are not bug free, so you have to fix them and test again. Dynamic classloading relieves you from having to restart iQgen every time you make a tiny change to a class. The only thing you have to do is to recompile your helper classes and start generation again.

Of course iQgen has to know where to find these classes. The properties enables you to define a directory from which iQgen will reload the classes for every generation process! (see Properties/Dirs)

The example itself generates one IDL file for the model.

Here is a complete list of files of this example:

DirectoryFileComment
./classloading.iqpProject file for this example
./build.xmlAnt Script for Generation
modelmodel.xmiModel XMI file
modelmodel.zargoArgoUML model file
templatesmain.jspModel element to template mapping
templatesidl.jspCreates the IDL output
classes/com/innoq/iqgen/classloadingtemplatesAttributeList.javaContainer for attributes and associations
classes/com/innoq/iqgen/classloadingtemplatesAttribute.javaAttribute Wrapper
classes/com/innoq/iqgen/classloadingtemplatesSequence.javaAssociation Wrapper

UML Profile

The UML profile looks like this:

  • only Struct and Interface are allowed as stereotypes

  • the stereotype Struct maps to IDL struct

  • the stereotype Interface maps to IDL interface

  • every navigable association must be named with a rolename

Model

The model describes a simple message board. The interface to the message board is the board itself. You are able to login, logout, add a message (addMessage) and add a reply to a message (addReply). Entities are User and Message. Every Message can have multiple replies which are also messages. In addition it is possible to add an Attachment to every Message.

Figure 2.6. Simple message board model

Simple message board model

Note

This example does not produce a complete runnable application it only generates the compilable IDL for the model.

Templates

First of all: If you try to verify the generated IDL file you have to download an IDL compiler. The JDK IDL compiler idlj.exe does not support forward declarations, which are required for this example.

In structs we have to list all attributes and navigable associations. For this purpose we write a helper class AttributeList. Its init method iterates over all attributes and associations. For an attribute and an association with multiplicity one an Attribute will be created and for an association with multiplicity many a Sequence will be created. In order to take advantage of the dynamic reloading feature for the helper class, we place it in the classes directory.

Finally we are able to iterate over the resulting collection in idl.jsp:

[...]
struct <%=getMetaModel().getName(_struct)%> {
<iqgen:foreach group="<%=new AttributeList(getMetaModel(),_struct).getElements()%>" item="_attribute" 
                    type="com.innoq.iqgen.classloading.Attribute">
   <%=getProperty(_attribute.getTypeName(),_attribute.getTypeName())%> <%=_attribute.getName()%>;
</iqgen:foreach>
}; // <%=getMetaModel().getName(_struct)%>
[...]                    

Generation

Open the project file /samples/getting_started/classloading/classloading.iqp and load the model. Set the Properties/Dirs/User Classes to C:\iqgen\samples\getting_started\classloading\classes (or where else your sample is located!). Press the Generate button.

A single file should have been generated. Try to make an IDL compilation of this file (maybe use JacORB ). It will lead to the following exception:

$ ./idl.bat Classloading.idl
Error in Classloading.idl, line:42(13): Declarator attachment already defined in scope.
 Attachment
Can't recover from previous error(s), giving up.
 : parse error: null                    

The problem is that the type Attachment is equal to the attribute name attachment!

How do we solve this problem?

We can change the getName method in com.innoq.iqgen.classloading.Attribute to:

public class Attribute {
[...]
   public String getName() {
      //old : return metamodel.getName(clazz);
      return "m" + StringHelper.fu(metamodel.getName(clazz));
   }
[...]
}                    

Just recompile the Attribute class and regenerate the model - now the IDL compilation should work just fine!

Activity diagrams

In this example we will show how to use activity diagrams to connect some HTML pages and simulate a simple screenflow. The content of the HTML pages is added as HTML to the modelelement documentation which we use to generate some visual content.

Here is a complete list of files of this example:

DirectoryFileComment
./activity.iqpProject file for this example
./build.xmlAnt Script for Generation
modelactivity.xmiModel XMI file
modelactivity.zargoArgoUML model file
templatesmain.jspModel element to template mapping
templatesform.jspCreates a HTML form
templatesindex.jspCreates a HTML index site

UML Profile

The UML profile looks like this:

  • Every State will produce a form

  • The transitions will be linked together in the index page

  • The workflow will be represented by incoming and outgoing transitions

Model

The model describes a login screenflow:

Figure 2.7. Login flow

Login flow

Chapter 3. Design Considerations

Does generating Code make Sense?

As with any tool, code generation and MDA is not a silver bullet. The key to successfully applying it to your project is to decide when this makes sense, and when it doesn't.

The following list includes the main indicators that your project might benefit from using a generative approach:

  • You have few business model elements, such as entities and processes, but a complicated infrastructure

  • You are using a technology that requires you to specify information in multiple places, yet maintain consistency (such as J2EE)

  • There is a need to isolate technical changes from changes in business requirements

There are also some indicators that a generative approach might not be the best tool for the job:

  • The project's focus is largely on algorithms, not largely static structure

  • You are building a low-level component, such as an I/O library

  • Your project is trivial and small

As with any recommendation, these guidelines are not intended to be applied without careful consideration. In general, most developers start building a prototype, and while doing so, recognize repetitive elements. This is generally the best way to find out whether you should use a generative approach in your project.

Good and Bad Code Generation

Once you have decided to use a generative approach in your development effort, it is a good idea to apply some architectural guidelines as to how to use it:

  • In general, you should try to meet the goal that all of the generated code must be at least as good as if it had been written manually. While not always possible, the idea of this goal is to avoid using code generation to circumvent problems with the underlying architecture and frameworks.

  • While code generation can sometimes improve performance, you need to be careful to avoid the dreaded “code bloat” symptom. Since generating code is so easy, you might find yourself with a million lines of code, where a lot of them are basically just identical, with only minor changes. Your underlying platform will often allow you to solve these problems by building libraries or frameworks. Use this approach, and augment it with code generation where your platform does not provide the needed means.

Generic vs. Generative Solutions

A well-known, and in our opinion, false assertion about code generation is, that it is a sign of a bad design to need something like this at all. There are, of course, cases where this is true. Most of the time, though, you need to be concerned about the division of your solutions into “generic” and “generative”, and there is most definitely no single best strategy here.

Consider, for example, mapping objects, their relations, and their associations, to code. One way to address this is to statically type your classes according to your model - have a get and set method for your attributes, a Java class for each model class, use e.g. java.util.Vector to contain associated objects. If you want to do this, and have a model that exceeds trivial complexity, a generative approach - i.e., using iQgen - is a perfect match.

On the other hand, you could also define a class called ApplicationObject with a java.util.HashMap to hold the attributes, keyed by their name. You could then change your business model (to a certain degree) without touching your code, too.

Which of these solutions is better? Clearly, there is no simple answer to this question, since it depends very much on your specific requirements. Quite often, a generative approach will improve performance and make code easier to read, since it is a lot more explicit than the generic solution. Generic solutions work at compile time, though, so sometimes they might be too inflexible for a given problem. Generating code can also significantly enhance your code base, which might hurt both performance at run time and turn-around cycles at development time. Quite often, a thin veneer that is generated at compile time and wraps the generic object structure is a possible solution.

In summary, there can be no clear, universal preference to either solution. Each project requires careful consideration of the requirements at hand, and to find the right balance requires a skilled software architect.

UML Profile Design

Designing a UML profile is a technically simple task, but should be done with great care nonetheless. Essentially, the UML profile for your project is just a set of possible stereotypes and tagged values that model elements can be annotated with. Their role, though, is very important, since they define the language you can work with as you model your domain.

You should strive to enable the creation of models that are simple enough to be understood, yet formal enough to enable code generation. In your iQgen templates, you can use this information to map model constructs to system artifacts. Because of this, having a large set of stereotypes and tagged values to finely control what kind of output to generate makes building templates easy, but burdens you (or whoever creates the model) with having to decide which element to chose for a given purpose.

From applying an MDA approach in a significant number of projects, our experience is that it's best to err on the side of too few stereotypes and tagged values and accept having to write more complicated templates. While this will increase the effort in setting up the infrastructure, templates can almost always be changed easier than a complex model.

It's also a good idea not to clutter your UML profile with low-level, technical details. This cannot be avoided completely. Still, it makes sense to e.g. not introduce a stereotype such as “EntityBean”, but rather opt for “Entity” - although you might consider a J2EE Entity Bean to be the best match in a given scenario, it should be possible to change this to some other mechanism (such as a non-J2EE persistence framework) without having to modify the model. Of course the name does not have any inherent meaning for iQgen, so it would be possible to generate, say, a C# class from a model element stereotyped with “MessageDrivenBean”, but this clearly does not make things any clearer.

Forward Engineering & the Development Process

iQgen follows a strict forward engineering approach, as opposed to other well known strategies such as reverse engineering or round-trip engineering. What this means for you is that you need to be careful to make any changes in the appropriate place - either in the model or inside the protected areas in your generated artifacts. A failure to do so will result in your code being overwritten unintentionally, resulting in code loss. To address this, your development process should be adjusted to match the generative approach to software development.

It's tempting to view this as a disadvantage, and require that every artifact in the system should be modifiable with whatever tool is best suited to the purpose. But the generation of multiple artifacts from a simpler, central source element raises productivity so much that you will soon get used to it and appreciate the benefits. An obvious analogy to the classical compile step can be made, and after all, you would not expect to be able to modify the machine (or VM) code emitted by a language compiler.

Embedding Code Generation in your Development Cycle

The first step to take when introducing a generative approach is to embed the code generation process into your processing chain. In general, this means that you should generate code from within your build scripts. The iQgen Ant integration allows you to call iQgen from within your Ant scripts. If you prefer make or some other build management tool, you can use the command line tools.

As with other software artifacts, you should take care to put your source model under configuration management control. Depending on your CASE tool of choice, you can either version the model file itself or only the XMI export. While the first choice is preferable, some tools don't offer this possibility - most notably those that are based on some centralized repository. They do, however, usually offer some built-in versioning mechanism instead.

As a result, your build cycle will roughly resemble the followi