Velocity Evaluation
Overview
Just like StringTemplate, Velocity is a library to be used in java programs in order to fill data into template strings. The java code is responsable for reading the template, associating a value to each attribute and writting the result to a stream.
Unlike StringTemplate, method calls are allowed to take arguments hence side-effects are possible (See the section on multiple source combination)
Reflection is used to extract information from objects either by calling getter methods or directly accesing public fields for properties, and parametrized method calls. The value of the attributes in the template is the result of calling toString() on the referred object.
Conditionals
The conditional operator:
#if(expr)
## if block
#elseif (expr)
## else-if block
#else
## else block
#end
Expr is evaluated and if the result is the boolean true or non-null then the
if-block is evaluated. Equivalents tests, logical NOT, AND, OR and numerical comparisons are allowed.
Iteration
Iteration is implemented with a syntax similar to the new for loop in Java:
#foreach($item in $itemList)
#end
Sorting
Parametrized methods in the model or in the template with complexity added
Multiple data sources
Multiple source can be combined by using code similar to this one:
public class Model {
private VelocityContext context;
public Model() {
context = new VelocityContext();
// the default model that is used to add datasources
context.put("model", this);
}
// binds and attribute to another object (datasource)
public void bind(String key, String pluginName, String altPath) {
/* gets the plugin from the list of registered ones or by loading
it from the alternate path */
context.put(key, plugin);
}
public VelocityContext getContext() {
return context;
}
public static void main(String [] args) throws Exception {
Velocity.init();
StringWriter sw = new StringWriter();
Model master = new Model();
Velocity.mergeTemplate("test.vm", master.getContext(), sw);
System.out.println(sw.toString());
}
}
The test.vm template:
$model.bind("dataSource1", "argouml", "somePath")
$model.bind("dataSource2", "reqrtool", "somePath")
## calls to methods for the two datasource-objects are valid here
Tools
The library comes under Apache License 2.0. An Eclipse plugin (http://velocitywebedit.sourceforge.net/) is available under the GPL, another one does not seem to be maintained (http://sourceforge.net/projects/veloedit). Modes for Emacs, JEdit, UltraEdit, TextPad are available.
Code
- Shows a subset of classes based on the name of the containing
package in chapter 1.
- For each of these classes,
shows all the names and types of the attributes.
For those classes that doesn't have attributes include instead
the text "No attributes."
#foreach($package in $packages)
<h2>$package.getName()</h2>
<ul>
#foreach($class in $package.getClasses())
<li>$class.getName()
#set($attrs = $class.getAttributes())
#if(attrs)
#for($attr in $attrs)
$attr.getName() $attr.getType()
#end
#else
No attributes.
#end
</li>
#end
</ul>
#end
- Shows a subset of classes based on the name of one of
the stereotypes in chapter 2.
- For each of these classes,
shows the signature of all the operations including
return value,
direction, name, and type of each parameter.
Each method as a bullet in a bulleted list.
#foreach($stereotype in $stereotypeList)
<h2>$stereotype.getName()</h2>
#foreach($class in $classList)
<ul>
#if ($class.hasStereotype($stereotype.getName()))
<li>
Class: $class.getName();
<ul>
#foreach($operation in $class.getOperations())
<li>
Name: $operation.getName()
Type: $operation.getType()
Parameters:
#foreach($parameter in operation.getParameters())
$parameter.getName():$parameter.getType()
#end
</li>
#end
</ul>
</li>
#end
</ul>
#end
#end
- Show a subset of classes based on the existance of a parameter
named "something" in any of the operations in the class in chapter 3.
#foreach($class in $classList)
#set( $found = false )
#foreach($operation in $class.getOperations())
#foreach($parameter in $operation.getParameters())
#if($parameter.getName() == something)
#set( $found = true)
#end
#end
#end
#if($found)
$class.getName()
#end
#end
- For each of these classes,
if they contain operations other than the one named "something",
show these in a table with one operation on each line with
the operation name in the first column and then one column per
distinct type for all parameters with the names of the parameters
filled in the table.
For those classes that doesn't have any other operations,
include instead the text "No other operations."
#foreach($class in $classList)
#set( $found = false )
#set( $others = false )
#foreach($operation in $class.getOperations())
#foreach($parameter in $operation.getParameters())
#if($parameter.getName() == something)
#set( $found = true)
#else
#set( $others = true)
#end
#end
#end
#if($found)
$class.getName()
#if(others)
<table>
#foreach($operation in $class.getOperations())
<tr>
<td>$operation.getName()<td>
#foreach($parameter in $operation.getParameters())
<td>$parameter.getName():$parameter.getType()<td>
#end
</tr>
#end
</table>
#else
No other operations
#end
#end
#end
| Linus attempt at this |
#foreach($class in $classList)
#set( $found = false )
#set( $others = false )
#set( $types = emptyset )
#foreach($operation in $class.getOperations())
#foreach($parameter in $operation.getParameters())
#if($parameter.getName() == something)
#set( $found = true)
#else
#set( $others = true)
#foreach(parameter in $operation.getParameters())
#set( $types = union($types, createOneElementSet($parameter) ) )
#end
#end
#end
#end
#if($found)
$class.getName()
#if(others)
<table>
<tr>
<th>Operation</th>
#foreach($type in $types)
<th>$type.getName()</th>
#end
</tr>
#foreach($operation in $class.getOperations())
<tr>
<td>$operation.getName()</td>
#foreach($type in $types)
<td>
#foreach($parameter in $operation.getParameters())
#if ($parameter.getType() == $type)
$parameter.getName()
#end
#end
</td>
#end
</tr>
#end
</table>
#else
No other operations
#end
#end
#end
|
- Show all use case diagrams in chapter 4
- Under each use case diagram, a list of actors and a list of use cases
both with their explanations.
## naming convention assumed and the model takes care of creating the images
#foreach($diagram in diagramList)
<img src="${diagram.getName()}.png" alt="${diagram.getName()}"/>
<h3>Actors</h3>
<ul>
#foreach($actor in $actorList)
<li>$actor.getName() - $actor.getExplenation()</li>
#end
</ul>
<h3>Usecases</h3>
<ul>
#foreach($usecase in $usecaseList)
<li>$usecase.getName() - $usecase.getExplenation()</li>
#end
</ul>
#end
- Show the use cases that are linked to
a requirement (requirements fetched from some other tool than
argouml indexed on the use case names) in chapter 5.
- Under each use case, show the requirement text.
Note: it is assumed that a plugin is registered or that a serialized model is provided
at the indicated path.
$model.bind("requiremetsSource", "identifierForPlugin", "orPathToPlugin")
#foreach($usecase in usecaseList)
$usecase.getName()
<ul>
#foreact($requirement in requiremetsSource.getRequirementList())
#if(usecase.getName() == requirement.getName())
<li>$requirement.getText()</li>
#end
#end
</ul>
#end
- Create a template that creates a html site with two frames.
One tree on the left with all actors, use cases, classes, attributes,
operations,
and then one page per actor, class, use case.
Note:The code combinining the two frames is static. The tree frame is generated
using a single template, the detailed frames are generated by applying templates specific for
actor/usecase/class etc. Calling the template and writing the file for each item must be done
in code.
Notes
- Length - easy to learn
- Complexity - the template author must be aware of the interfaces of the models as most is done through method calls; imperative language.
- Error prone
- attributes that are not bind are copied as plain-text in the result
- floating point paramters seem to confuse the parser
- Error spoting - large amount of code might make errors hard to spot