Login | Register
My pages Projects Community openCollabNet

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