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 documentation 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, right here.

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.