Velocity
Tecnologia de geração baseada em template mantida pela comunidade Apache. Proposta inicialmente para geração de conteúdo HTML dinâmico, passou a ser usada como uma solução de template de propósito geral.
Geração de código com Velocity
Esse exemplo consiste em adaptar um avaliador de expressões de acordo com:
- o tipo da expressão (int ou double)
- suporte opcional a geração de uma representação String das expressões
- suporte alternativo a expressões básicas (soma e subtração) ou avançada (que inclui divisão e multiplicação)
Para usar o velocity, usamos a tarefa
texen do ANT, específica para geração de conteúdo texto exportado para arquivos. Para isso, é necessário adicionar duas bibliotecas velocity ao classpath do ANT (isso pode ser feito via eclipse, nas página de preferências do ANT). As bibliotecas (arquivos jars), estão disponíveis no arquivo:
velocity-1.5.zip
Abaixo, é apresentado um exemplo de arquivo build.xml que pode ser usado para fazer a geração de código fonte.
<project name="HtmlGenerator" default="main" basedir=".">
<taskdef name="texen" classname="org.apache.velocity.texen.ant.TexenTask" />
<!-- ============================================================= -->
<!-- G E N E R A T E JAVA SOURCE CODE-->
<!-- ============================================================= -->
<!-- This target will generate a set of Java source code pages -->
<!-- based on the information in our control context. -->
<!-- ============================================================= -->
<target name="main">
<echo message="+------------------------------------------+" />
<echo message="| |" />
<echo message="| Generating JAVA source code! |" />
<echo message="| |" />
<echo message="+------------------------------------------+" />
<texen controlTemplate="ExpressionControl.vm" outputDirectory="./target" templatePath="." outputFile="generation.report" />
</target>
</project>
O processo de geração é customizado com o arquivo
ExpressionControl.vm, que pode ser adaptado para gerar diferentes membros da linha de produtos. Optamos por disponibilizar a forma mais simples de implementar esse tipo de adaptação: as propriedades são definidas no próprio arquivo
ExpressionControl.vm. Usa solução mais flexível seria a utilização de arquivos de propriedades para definir as propriedades de uma instância. Abaixo um exemplo do arquivo
ExpressionControl.vm. Esse exemplo define um produto com as seguintes features:
- int como tipo base das expressões (type=int)
- sem suporte a representacao string das expressoes (print=false)
- sem suporte a operações complementares (extended=false)
#set ($type = "int")
#set ($print = true)
#set ($extended = true)
$generator.parse("Expression.vm", "Expression.java", "type", $type)
$generator.parse("Value.vm", "Value.java", "type", $type)
$generator.parse("BinaryExp.vm", "BinaryExp.java", "type", $type)
$generator.parse("AddExp.vm", "AddExp.java", "type", $type)
$generator.parse("SubExp.vm", "SubExp.java", "type", $type)
#if($extended == true)
$generator.parse("MultExp.vm", "MultExp.java", "type", $type)
$generator.parse("DivisionExp.vm", "DivisionExp.java", "type", $type)
#end
Por fim, criamos templates velocity para cada classe ou interface que varia na linha de produtos. Esses arquivos são referenciados, ou processados, pelas chamadas $generator.parse do arquivo de controle.
Arquivo Expression.vm
package br.ufpe.cin.lps.base.expression;
public interface Expression {
public $type eval();
#if($print)
public String print();
#end
Arquivo Value.vm
package br.ufpe.expression;
public class Value implements AbstractExpression {
private $type value;
public Value($type value) {
this.value = value;
}
public $type eval() {
return value;
}
#if($print)
public String print() {
return "" + value;
}
#end
}
Arquivo Binary.vm
package br.ufpe.cin.lps.elp.base.expression;
public abstract class BinaryExp implements Expression {
private Expression left;
private Expression right;
private String operator;
public BinaryExp(Expression left, Expression right, String operator) {
this.left = left;
this.right = right;
this.operator = operator;
}
public Expression getLeft() {
return left;
}
public Expression getRight() {
return right;
}
public String getOperator() {
return operator;
}
#if($print)
public String print() {
return left.print() + operator + right.print();
}
#end
}
Arquivo AddExp.vm
package br.ufpe.cin.lps.elp.base.expression;
public class AddExp extends BinaryExp {
public AddExp(Expression left, Expression right) {
super(left, right, "+");
}
public $type eval() {
return left.eval() + right.eval();
}
}
Exercício
Criar templates do velocity para as expressões de subtração, multiplicação e divisão. Note que o exemplo de arquivo de controle faz referência a esses templates. O processo de build só funciona com os mesmos. Executar gerações para diferentes configurações dos produtos e analisar os resultados.
--
RodrigoBonifacio - 26 Aug 2008