Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Apache Velocity

Panoramica, con concetti teorici ed esempio pratico, su Velocity, il templating engine sviluppato da Apache
Panoramica, con concetti teorici ed esempio pratico, su Velocity, il templating engine sviluppato da Apache
Link copiato negli appunti

Chi si occupa di sviluppo software, spesso si trova ad utilizzare tool grafici che consentono la modellazione di un sistema. Pensiamo ai tanti software che consentono di disegnare un diagramma delle classi UML o una base di dati attraverso diagrammi ER. La maggior parte di questi software consente generalmente di esportare direttamente il codice sorgente in modo da non dover scrivere a mano quello che già è stato modellato.

Dietro la creazione automatica del codice si nasconde uno degli strumenti più utili per chi si occupa di creare e utilizzare template per la rappresentazione di informazioni: Apache Velocity.

Velocity fa parte di quegli strumenti di sviluppo noti come generatori di codice ed è senza dubbio quello maggiormente utilizzato in ambiente Java, anche perchè sviluppato nello stesso linguaggio e facilmente integrabile all'interno delle applicazioni Java based.

Concetto teorico

Un generatore di codice è un oggetto che consente di definire delle regole (un template) per la generazione finale di un documento (un codice sorgente, una pagina HTML, ...) con informazioni che possono cambiare dinamicamente.

L'idea che dà valore alla presenza di questi generatori dinamici è quella di rendere la rappresentazione finale indipendente dal dato da rappresentare. Un po' il tema ricorrente dell'informatica moderna, disaccoppiare in modo da poter riutilizzare in maniera sempre differente i dati, le informazioni in possesso, che sono il vero valore stabile di qualsiasi organizzazione aziendale.

L'idea che viene applicata al generatore del codice (nel nostro caso Velocity, ma il concetto è estendibile a tutti i tool di questa categoria) è quella della trasformazione che forse già conoscete in ambito XML con la trasformazione XSL.

Ci sono delle informazioni che vogliamo rappresentare (che chiameremo Data) e un Template che ne definisce delle regole. La rappresentazione finale passa per il motore del template, che si aspetta in input sia il Data che il Template: qui avviene il merge delle informazioni (in Data) con la struttura della rappresentazione (in Template). Il processo segue delle regole sintattiche presenti all'interno del Template al fine di rappresentare opportunamente le informazioni di Data.

Come esempio pratico consideriamo la generazione del codice di una pagina Web in un linguaggio dinamico. È grazie all'utilizzo di questi concetti che è possibile creare rappresentazioni dinamiche di una pagina Web (si immagini JSP). Si definiscono delle regole, che rappresentano il contratto tra la fase di visualizzazione (chi disegna la pagina) e la fase di definizione della logica (chi raccoglie i dati da visualizzare).

Listato 1. Template

$nome
$cognome

Hello world, $nome $cognome !

Le variabili nome e cognome rappresentano le informazioni che chi si occupa della logica dovrà valorizzare opportunamente (ad esempio collegandosi ad un database).

Listato 2. Valorizzazione delle variabili

X=createTemplate()
x.use("nome","Pasquale")
x.use("cognome", "Congiusti")

x.transform()

Lo pseudocodice scritto ci illustra come la logica di rappresentazione finale verrà scritta al fine di effettuare la trasformazione tra i dati e quindi il risultato:

Hello World, Pasquale Congiusti !

Esempio pratico

Di sicuro l'applicazione di questa tipologia di trasformatori va oltre il semplice "Hello World" illustrato. Un uso massiccio viene effettuato nella fase di visualizzazione di un Web server, dove al template vengono associati i dati dinamici. Ancora, altro tipico utilizzo è quello fatto negli strumenti IDE dove la programmazione visuale si traduce in maniera molto rapida nella generazione della struttura del codice.

In quest'ultimo caso viene utile anche la possibilità di mantenere lo stesso dato modificando la sua rappresentazione. Si pensi ad esempio ad un diagramma UML e alla sua codifica in Java o in C++. Il diagramma rimane identico, ma la generazione del codice è diversa e sarà semplice creando un nuovo template associato al linguaggio desiderato.

Vediamo ora un'applicazione pratica che ci mostra con un semplice esempio come utilizzare Velocity. Il nostro obiettivo è creare una newsletter in maniera dinamica, quindi personalizzarla con contenuti dinamici e con informazioni specifiche di ogni utente.

L'entità che rappresenta l'utente sarà una semplice stringa (che ne definisce il nome o il soprannome), mentre l'entità che definisce la notizia è una classe che chiamiamo New, che espone i metodi getter e setter per gli attributi title e article (titolo e contenuto dell'articolo), due stringhe.

Definiamo ora il template di seguito (si tratta in linea di massima di una pagina HTML):

Listato 3. Template della newsletter

## template.vm

<html>
<head>
<title>A simple newsletter</title>
</head>

<body>
<h1>Hello $name</h1>
<hr/>
<h2>Latest news</h2>
#foreach($new in $news)  
  <p>
    <div>$new.title</div>
    <div>$new.article</div>
  </p>
#end
</body>

Per la sintassi completa di Velocity vi rimando alle tante risorse che trovate su Internet e al sito dove avete effettuato il download. Per l'esempio è sufficiente conoscere la definizione delle variabili che rappresentano il contratto, definite mediante il simbolo dollaro ($).

Come vediamo dal codice avremo $name e $news. Il generatore di codice riconosce automaticamente queste variabili come classi Java, quindi attraverso la notazione puntata ($x.y) abbiamo accesso ai metodi get degli attributi pubblici. In questo caso è presente un ciclo di for (il cancelletto, #, rappresenta l'inizio di un generico statement Velocity) dove viene definita la variabile $new, che rappresenta l'iesimo oggetto contenuto in $news.

Per poter generare il codice è ora necessario utilizzare l'engine Velocity e passare le due variabili. Una rappresenta il nome dell'utente, l'altra una lista di New (supponiamo di recuperarle entrambe in maniera dinamica).

Listato 4. Engine dell'applicazione

public class Main {
  public static void main(String[] args) throws IOException {
    BufferedWriter writer = null;
    //Nella variabile users manteniamo la lista utenti (Stringhe)
    String[] users=new String[3];
    ArrayList<New> news=new ArrayList<New>();

    //Riempiamo le liste di utenti e contenuti
    initialize(users);
    initialize(news);

    for (int i = 0; i < users.length; i++) {
      try{
        String user=users[i];
        
        //Nel context definiamo il contratto (tramite il nome delle variabili e il relativo tipo)
        VelocityContext context = new VelocityContext();
        context.put("name", user);
        context.put("news", news);
        
        //Apriamo un template, sul file definito
        Template template = Velocity.getTemplate("template.vm");
        //e creiamo un flusso di scrittura (in questo caso su file system)
        writer = new BufferedWriter(new FileWriter(user+"_news.html"));
        
        //Effettuiamo il merge del contesto con il flusso di scrittura
        template.merge(context, writer);
      }catch(Exception e){
        e.printStackTrace();
      }
      finally{
        writer.flush();
        writer.close();
      }
    }
  }
...
}

La classe creata è un main, ma è evidente che la logica puo' essere inserita in qualsiasi flusso logico. Definiamo due liste: una rappresentante gli utenti e l'altra la lista di oggetti da rappresentare. Effettuiamo un ciclo sugli utenti e per ognuno di essi creiamo un Context a cui associamo le variabili. Al contesto applichiamo il template e definiamo infine il flusso di scrittura (in questo caso un file HTML, ma è evidente come possa essere uno stream su un socket).

Il risultato è una pagina Web simile alla seguente:

Figura 1. Risultato finale
Risultato finale

Ti consigliamo anche