Tigerstripe Advanced Plugin Tutorial

This tutorial builds upon the concepts discussed in the Simple Plugin Tutorial. It introduces different rule types, shows how to incorporate more information into your templates and develop java helper classes to simplify template writing.

Defining Global Rules

In some situations, you may desire or need to create a file that contains information about multiple artifacts. For example, a single XML file that contains information about all of the artifacts in a project or an HTML index page that provides links to pages about each entity. In this case you would define a Global Rule.

In the following example you will create a very simplistic XML schema that has elements for each Entity in the model. Note: The validity of this schema is questionable; it is intended purely as an example of a Global Rule.

type="$attribute.Type.Name" - Scans the model to obtain the name of the attribute type.

Note: You can obtain a more complete picture of the model structure by looking at the javaDoc for the Tigerstripe external API.

2. Create a Global rule that points to the template you created.
You accomplish this in the same way you created an Artifact Rule. Refer to Define a Plug-in Rule for more information. There are actually two types of Global Rule - for this rule, select the "Simple Run Rule" from the drop-down list - this should be the default.

3. Click Save to save your changes.

The next time you generate a Project with this plugin enabled, you should get a schema file (schema.xsd) with content similar to the following:

Defining Model Based Rules

As a further variant of the rules we defined above, you may desire or need to create a file that contains information about the artifacts that exist in each "model" that is referenced from your own model project. In this case you would define a Model Based Rule.

Model Based Rules are executed once per model that is found in the depndency hierachy of a project. This will include any refernced modelas an and installed modules. The rule will walk the hiearchy tree to discover transitive depndencies in the tree. There are a few differences from Artifact Rules:
Creating a Model Based Rule follows the same process as creating an Artifact Rule, however there is less information to enter upon creation.

In the following example you will create a very simplistic XML schema that has elements for each Entity in each model in teh dependecny tree. Note: The validity of this schema is questionable; it is intended purely as an example of a Model Based Rule.

This is very similar to the globalTemplate we saw above, but there is one key difference.

#foreach ($entity in $moduleEntities) ...... #end - The collection that is being iterated over is different! the $moduleEntities collection willbe limited to the entities in any given model in the tree.

2. When defining an output file Name for the rule, you will most likeley need to use the model Identity - something like ${modelId}.

Other than that, creating a model rule is very similar to creating a global rule.

Using Java Wrappers

A Wrapper is a Java class that implements the IArtifactWraper interface specified in the Tigerstripe External API. A wrapper is a set of code around a core Tigerstripe artifact that enables custom behaviour to be added to artifact. Appropriate use of a Wrapper can greatly simplify templates and enhance their readability.

In the Wrapper you define methods to manipulate the information available from the artifact, project etc, or look-up additional data. Some examples of method usage within a model are:

Reformat data - You may want to translate a package name to a directory path name. For example, com.mycompany.models could become com/mycompany/models.

Note: You will need to "import" the IArtifactWrapper, IPluginConfig and IArtifact interfaces for the Tigerstripe External API.

In this example, you will specify the type of your artifact to be IArtifact. This allows the model to be used for any artifact type. In many cases however, you may wish to create a more specific type of artifact, such as IManagedEntityArtifact. This allows access to methods on a particular artifact type. It is also possible to create a generic wrapper and inherit from that wrapper for each specific artifact type.

Note that through the pluginConfig object that is passed, you can gain access to project properties.

Having created your wrapper, you will need to refer to it in a template and then set up a rule to pass the model to the template.

1. Create your template. This procedure is the same as previously outlined, but within the template you will make reference to methods on the wrapper.

## This is wrapperTemplate.vm
##
// This file was generated using $templateName.
##
// In this case the artifact Name ($artifact.Name) ,
// is not the same as the model Name ($wrapper.Name).
public interface ${wrapper.Name} {
public String get${wrapper.KeyName};
}

2. Create a new rule as described in the Simple Plugin Tutorial. However, in the Wrapper Class field, browse to the Wrapper Class that you created above. In the Wrapper Class Name text box, enter the name by which the wrapper will be referred to within your template.

In this tutorial, name your Wrapper class wrapper . Hence the use of $wrapper in the above template example.

Note: The Output File definition can contain references to wrapper methods by using the ${model.xxx} syntax.

The generated file for the Order entity will be in a directory based on it's package name, and will have the name OrderValue.out. It will contain a method called getOrderKey.

You could have easily achieved this result by using template functions, but as your processing becomes more and more complex, wrappers will become an essential part of your plug-ins.

Note: IArtifactWrapper replaces the old IArtifactModel which had the same basic behaviour.

Artifact Filters

(This feature only applies to Artifact Rules)

Sometimes you may need to run through a subset of artifacts of a given Artifact type. Rather than code a rule into your template, you can specify an Artifact Filter that will limit the artifacts that are processed in the template. This will keep your templates simple and easy to understand.

Artifact Filters are defined in a similar manner to [[Tigerstripe_Glossary#Model Class|Models]. That is, Artifact Filters are Java classes in the src directory of your plugin that implement the IArtifactModel interface. The filter needs to implement a single select method and any artifact that returns a result of true, is passed to the template engine for further processing.

In the following filter, only artifacts that have a Stereotype of name Version are accepted and all other artifacts are rejected. For a detailed discussion of Stereotypes see the Advanced Stereotypes to Tigerstripe Models tutorial.

Note: Remember to deploy your plug-in when you change a rule definition.

Velocity Context Definitions

Another way to simplify templates is to create a Utility class. A Utility class contains commonly used methods; a typical case might be a set of String manipulation utilities. These could be third party utilities or your own.

3. Add Utility classes to your rule by adding them to the list of Velocity Context Definitions. Each definition (either your own or a reference to a .jar containing utilities) must have an entry with a name and a path . The name is used in the template to identify the specific utility class.

In your template, you can then use these methods with the $utilName.methodName(arg) syntax. For example, using the utility as defined above, which has been added with the name myUtils:

public $attribute.Type.Name get${myUtils.capitalize($attribute.Name)}();

Note: In this case the ${ } syntax for Velocity can help when your utility function is adjacent to other text.

If you call a method that does not exist, Velocity will simply leave the reference in place. For example, if you mistype the above function name and run your plugin, you may find a line (such as the one outlined below) in your output file:

public String get${myUtils.capitulate(Details)}();

Logging and reporting statuses

org.eclipse.tigerstripe.workbench.plugins.PluginLog class provides ability to inform end user about generation details. You can use PluginLog.log* methods to log a message into the plugin specific log file. To display a message into Generate Result dialog box your should use PluginLog.reportStatus(IStatus) method.

The basic scenario is that, when a rule runs a set of objects are passed to velocity which renders the output, as described in the template specified for that rule.

The set of Java objects that are passed to velocity is the "context".

A rule *always* sends a fixed set of java objects to velocity - these are described in the section titled "Default Velocity Context Definitions" in the miscellany tutorial. Looking at this, you can see that the default context contains things such as the $project, $pluginConfig, and $artifact (for an artifact rule). There are the objects that you will use in a template.

The template only knows about those objects which the rule passes to it, and can only operate over those items.

By specifying additional "Velocity Context Entries" in a rule, you can increase the set of objects which the template can access. This is most often used for passing utility programs in that will be used for formatting data, or access external data.

As an example you might create a java utility class called MyUtils that reads an external xml file and makes the data available through some static methods such as getMyData(). By adding the class MyUtils to the list of Velocity Context Definitions in the rule, and giving it the name of "myUtils", in your template you can use $myUtils.MyData to execute the method and thus access your xml data.

Velocity Macros are a built-in velocity feature that can be used for writing a common function in the template. For example in a template that is generating java, you might have a fixed way of outputting comments - ie in a /*.....*/ block. This format requires that the text is surrounded by the right comment syntax , is at a fixed indent, the line is truncated to a given length and so on.Rather than write this code at every point you want a comment, you could write a macro that takes some text and renders the text in the right way. Every time you have a comment you simply call the macro, passing it the text of the comment as an argument.

If you enable this feature, the Tigerstripe Report will appear as TigerstripeReport.xml, and will include (in addition to other information about the project) a section for each Rule. These reports can be useful at runtime to determine what has been handled, filtered, and generated. An example extract from a plugin with a single Rule is shown below:

In this example, the initial section display information about the plugin', and the value of the Global Properties that have been set for this project. As a result, a childReport is created for each Rule in the plugin.

<matchedArtifacts> lists the qualified name for the artifacts that were passed to this rulebased on their Artifact Type and passed any defined filter.

<generatedFiles> lists the files generated relative to the output directory for your project.

Note : This description is not complete and there will be additional information in the report.