Mokabyte

Dal 1996, architetture, metodologie, sviluppo software

  • Argomenti
    • Programmazione & Linguaggi
      • Java
      • DataBase & elaborazione dei dati
      • Frameworks & Tools
      • Processi di sviluppo
    • Architetture dei sistemi
      • Sicurezza informatica
      • DevOps
    • Project Management
      • Organizzazione aziendale
      • HR
      • Soft skills
    • Lean/Agile
      • Scrum
      • Teoria della complessità
      • Apprendimento & Serious Gaming
    • Internet & Digital
      • Cultura & Società
      • Conferenze & Reportage
      • Marketing & eCommerce
    • Hardware & Tecnologia
      • Intelligenza artificiale
      • UX design & Grafica
  • Ultimo numero
  • Archivio
    • Archivio dal 2006 ad oggi
    • Il primo sito web – 1996-2005
  • Chi siamo
  • Ventennale
  • Libri
  • Contatti
Menu
  • Argomenti
    • Programmazione & Linguaggi
      • Java
      • DataBase & elaborazione dei dati
      • Frameworks & Tools
      • Processi di sviluppo
    • Architetture dei sistemi
      • Sicurezza informatica
      • DevOps
    • Project Management
      • Organizzazione aziendale
      • HR
      • Soft skills
    • Lean/Agile
      • Scrum
      • Teoria della complessità
      • Apprendimento & Serious Gaming
    • Internet & Digital
      • Cultura & Società
      • Conferenze & Reportage
      • Marketing & eCommerce
    • Hardware & Tecnologia
      • Intelligenza artificiale
      • UX design & Grafica
  • Ultimo numero
  • Archivio
    • Archivio dal 2006 ad oggi
    • Il primo sito web – 1996-2005
  • Chi siamo
  • Ventennale
  • Libri
  • Contatti
Cerca
Chiudi

Nel numero:

151 maggio
, anno 2010

Estendere Maven

Come scrivere un plug-in per Maven

Avatar

Francesco Benincasa

Ha iniziato il cammino dello sviluppatore con i linguaggi Pascal, COBOL, C/C++, Visual Basic. In seguito, ha intrapreso il sentiero del web in ASP. Ha conseguito la laurea in Ingegneria Informatica all‘università di Trieste nel 2002. Dal 2000 lavora principalmente in Java. Oggi si occupa di progettazione e sviluppo di architetture web su piattaforma Java. Si interessa anche di .NET e di grafica 3D.

MokaByte

Estendere Maven

Come scrivere un plug-in per Maven

Francesco Benincasa

Francesco Benincasa

  • Questo articolo parla di: Frameworks & Tools, Processi di sviluppo, Programmazione & Linguaggi

Apache Maven è uno strumento di gestione dei progetti, utilizzato per la realizzazione delle build e per moltri alti compiti importanti. La sua potenza e la sua versatilità lo rendono un‘ottima risorsa per tanti sviluppatori. In questo articolo si vedrà come realizzare un plug-in per Maven.

Introduzione

Maven [1] è un potente strumento per la gestione dei progetti per la piattaforma Java, con una moltitudine di plug-in già pronti. Nonostante ciò, a volte può essere necessario estendere ulteriormente le capacità di Maven a causa di particolari esigenze. Ad esempio, si può creare un plug-in per generare report custom legati al progetto o per inserire nella build le informazioni contenute nei log del source version control utilizzato.

Nel corso di questo articolo vengono presentati in modo pratico i passi necessari a realizzare un plug-in, che chiameremo Dummy, con le seguenti funzioni:

  • individua le dipendenze di un progetto e le scrive su un file di testo nella cartella di output del progetto;
  • verifica la possibilità di istanziare una o più classi appartenenti al progetto o alle sue dipendenze.

Implementare le funzioni appena esposte implica lo svolgimento delle seguenti attività all’interno del plug-in:

  • definire dei parametri in ingresso per il plug-in;
  • individuare l’elenco dei componenti da cui dipende il progetto;
  • individuare la cartella delle classi compilate;
  • caricare le classi compilate appartenenti al progetto;
  • scrivere un file nella cartella in cui il progetto viene creato.

Queste sono alcune delle attività di base che possono essere utilizzate per realizzare un qualsiasi plug-in.

Nel corso di questo articolo si userà l’IDE Eclipse 3.5 [2] con il plug-in di Maven [3] e con Java 1.6 (1.6.0_14). Si suppone che il lettore abbia sufficiente conoscenza dell’uso di Maven e di Eclipse.

Creazione del progetto

Realizzare lo scheletro del plug-in con Eclipse è semplice. Di seguito riportiamo i passi necessari a farlo.

Partendo dall’elenco di tipi di progetti è sufficiente selezionare il wizard relativo: Maven –> Maven Project.

 

 

Figura 1 – Selezione del wizard.

 

Premendo il pulsante Next si arriverà nello step illustrato in Figura 2.

 

 

Figura 2 – Step 1 del wizard.

Premendo il pulsante Next si arriverà alla schermata con la quale selezionare l’archetype da utilizzare. Per creare Dummy utilizzeremo maven-archetype-mojo.

 

 

Figura 3 – Selezione del tipo di progetto.

Giunti a questo punto sarà necessario inserire il GroupId e l’ArtifactId del progetto.

 

 

Figura 4 – Definizione dell’identificativo del plug-in.

A questo punto nel workspace verrà creato il progetto Dummy.

Mojo! Mojo!

Mojo sta per Maven plain Old Java Object ed è l’implementazione di un goal del plug-in. Può essere considerato come l’interfaccia con la quale il plug-in interagisce con il resto di Maven. Un plug-in può contenere uno o più oggetti mojo. All’interno del progetto Dummy (allegato scaricabile dal menu in alto a sinistra) si troverà un’unica classe denominata MyMojo, il mojo del plug-in. In [4] si trovano le specifiche relative ai mojo.

/**
 * Goal which touches a timestamp file.
 *
 * @goal mygoal
 *
 */
public class MyMojo extends AbstractMojo
{
        ...
        public void execute()
            throws MojoExecutionException
        {
            ...
        }
    ...
}

Il metodo che viene eseguito per l’esecuzione del goal è il metodo execute. Il mojo viene configurato mediante le annotazioni che si trovano nei JavaDoc. Nel JavaDoc della classe troviamo l’annotazione @goal che indica il nome del goal implementato dal plugin. Nel caso di Dummy l’annotazione avrà come valore mygoal.

Log

La classe AbstractMojo da cui deriva il mojo del nostro plugin, espone un logger per visualizzare a console tutti messaggi mediante la proprietà Log. I messaggi visualizzati possono essere di 4 tipi: debug, info, error, warn. Per utilizzarlo è sufficiente dichiarare una variabile e utilizzarla nel seguente modo:

...
Log log = getLog();
log.info(" *** Dummy Plugin ***");
...

Parametri

Dummy ha bisogno di ricevere dei parametri in ingresso. Per avere queste informazioni aggiungiamo le seguenti proprietà di istanza al mojo:

/**

 

 * The greeting to display.
 *
 * @parameter default-value="Hello World!"
 */
private String greeting;
/**
 * The class name to test
 * @parameter
 */
private List classNameList;
/**
 * @parameter default-value="${project}"
 */
private MavenProject mavenProject;
          /**
 * @parameter expression="${project.build.directory}"
 */
private File outputDirectory;
/**
 * @parameter expression="${project.build.outputDirectory}"
 */
private File buildDirectory;
/**
 * @parameter expression="${project.build.sourceDirectory}"
 */
private File inputDirectory;

L’uso dell’annotazione @parameter inserita nei javadoc di una proprietà permette di iniettare nella stessa il valore del parametro in ingresso definito per il plug-in. L’attributo greeting rappresenta un parametro passato in ingresso al plugin. Di default assume il valore “Hello World”. L’attributo classNameList rappresenta l’elenco delle classi che si desidera istanziare per prova e è di tipo List. I parametri in ingresso al mojo possono essere di vario tipo: string, long, double, boolean e perfino liste e mappe. L’attributo mavenProject è il componente che rappresenta il progetto in cui viene fatto girare il plugin. Esso viene utilizzato per recuperare le dipendenze del progetto. La classe MavenProject si trova nell’artifact maven-project: per risolvere la classe è necessario includerla nelle dipendenze del progetto mediante maven. Nella proprietà outputDirectory è iniettato il valore della variabile d’ambiente ${project.build.directory}, che rappresenta la cartella in cui avverrà la build del progetto. Gli attributi buildDirectory e inputDirectory sono stringhe nelle quali vengono iniettati i nomi delle cartelle rispettivamente di output e dei sorgenti.

Mediante l’attributo expression dell’annotazione @parameter, si possono usare le proprietà definite nel pom.xml o in qualsiasi risorsa processata da Maven. Il nome di una risorsa deve seguire la sintassi ${}. Si tenga presente che:

  • Le proprietà project.*: rappresentano le proprietà nel pom.xml (ad esempio project.groupId and project.version).
  • Le proprietà settings.*: rappresentano le proprietà in settings.xml.
  • Le proprietà env.*: rappresentano le variabili d’ambiente quali PATH e M2_HOME.

Per lavorare con le cartelle del progetto si utilizzano le variabili d’ambiente:

project.build.sourceDirectory
project.build.scriptSourceDirectory
project.build.testSourceDirectory
project.build.outputDirectory
project.build.testOutputDirectory
project.build.directory

Per ulteriori dettagli sui parametri si rimanda a [3]. Esistono diverse opzioni per definire il comportamento dell’annotazione @parameter. Nei casi affrontati in questo articolo se ne vedono solo una minima parte, per cui si consiglia di consultare [4] per approfondire l’argomento.

Class loader

Individuato da dove recuperare le classi, è necessario caricare in memoria i JAR e le classi del progetto. All’interno del codice allegato a questo articolo è presente una classe denominata DynamicClassLoader, il cui scopo è proprio quello di facilitare il caricamento in memoria delle classi del progetto. Essa deriva dalla classe loader URLClass. Per visualizzare i messaggi a console si utilizza un’istanza della classe Log, ereditata direttamente dalla classe padre di MyMojo.

Il metodo execute del mojo rappresenta il cuore del plug-in. Al suo interno si inserisce il codice necessario a recuperare dalla definizione del progetto le dipendenze:

...
// recuperiamo l'elenco delle dipendenze
Set set=(Set)mavenProject.getDependencyArtifacts();
List jars=new LinkedList();
...

Il codice relativo al caricamento in memoria delle classi:

try {
    // istanziamo ora delle classi con il DynamicClassLoader
    dyn = new DynamicClassLoader(buildDirectory.getAbsolutePath() 
          + File.separator, jars);
} catch (Exception e1) {
    log.error("Error " + e1.toString());
    e1.printStackTrace();
}

Per istanziare una classe del progetto si deve utilizzare il class loader che ha nel classpath la cartella delle classi compilate e l’elenco dei JAR delle dipendenze. Provare ad istanziare una classe con il class loader di default genera un’eccezione.

...
for (String item : classNameList) {
    try {
        // istanziamo ora delle classi con il DynamicClassLoader
        Class<?> clazz = Class.forName(item, true, dyn);
        temp = "Class instance " + clazz.toString() + " is ok!!";
        buffer.append(temp + "
");
        log.info(temp);
    } catch (Exception e1) {
        log.info("Error " + e1.toString());
        e1.printStackTrace();
    }
}
...

Scrittura di un file nella cartella di output

Nell’ultima parte della definizione del metodo execute è contenuto il codice necessario a scrivere su un file di testo nella cartella di output.

...
log.info("output file:" + outputDirectory.getAbsolutePath());
File f = outputDirectory;
if (!f.exists()) {
    f.mkdirs();
}
File file = new File(f, "dummyplugin.txt");
FileWriter w = null;
try {
    w = new FileWriter(file);
    w.write(buffer.toString());
} catch (IOException e) {
    throw new MojoExecutionException("Error creating file " + file, e);
} finally {
    if (w != null) {
        try {
            w.close();
        } catch (IOException e) {
            // ignore
        }
    }
}
...

Installazione

Per compilare il plug-in e installarlo nel repository locale è sufficiente eseguire Maven con il goal install. Per fare questo, con Eclipse è sufficiente eseguire la voce del menù di contesto del progetto Run as –> Maven install.

Figura 5 – Voce del menù di contesto per eseguire il goal install.

 

Uso del plug-in

Per sperimentare l’impiego del plug-in si è creato un altro progetto di esempio, basato sull’archetipo maven-archetype-webapp e denominato webprova. Con il menù di contesto dell’applicazione, si è aggiunto al progetto il plug-in dummy e la dipendenza a logj4. Il pom.xml di webprova si ritrova così a contenere il seguente codice:

...

log4j
log4j
1.2.15

...

e per il plugin:

    
        dummy
        Dummy
        0.0.1-SNAPSHOT
        
        
        compile
        
            mygoal
        
        
        
        

Oppure mediante l’interfaccia che Eclipse propone per la gestione grafica del pom.xml.

Figura 6 – Interfaccia per la gestione del pom.xml

L’unico aspetto della configurazione del plugin che deve essere scritto direttamente nel file pom.xml è la definizione dei parametri. Per il plugin dummy vengono definiti i parametri di configurazione greetings e classNameList:

    dummy
    Dummy
    0.0.1-SNAPSHOT
    
        
        compile
        
            mygoal
        
        
    
    
    Ciao mondo!!!
    
       webprova.Prova
       org.apache.log4j.Logger
    

Il parametro greetings è di tipo stringa e di conseguenza il suo valore può essere definito come corpo del tag omonimo. Il classNameList invece è stato definito come una lista di stringhe i cui singoli valori devono essere incapsulati in un tag param.

Dummy per essere eseguito correttamente, richiede la compilazione dei sorgenti dell’applicazione. Di conseguenza è stato agganciato alla fase di compilazione. Ogni volta che si procederà con la compilazione del progetto, verrà eseguito anche il goal del plugin. È anche possibile lanciare il goal stand alone del plugin mediante la sintassi groupID:artifactID:[version:]goal. Per l’esecuzione stand alone del plugin d’esempio si deve eseguire il goal:

mvn dummy:Dummy:mygoal

È possibile eliminare dalla linea di comando il package, includendolo nei package di default di ricerca nel file ${user.home}/.m2/settings.xml:

    dummy

In questo caso il comando diverrebbe

mvn Dummy:mygoal

A console, eseguendo il plugin si ottiene:

[INFO] ------------------------------------------------------------------------
[INFO]  *** Dummy Plugin ***
[INFO] ------------------------------------------------------------------------
[INFO] input dir:D:progettimavenPluginwokring3.5webprovasrcmainjava
[INFO] build dir:D:progettimavenPluginwokring3.5webprova	argetclasses
[INFO] output dir:D:progettimavenPluginwokring3.5webprova	arget
[INFO] Artifact=junit 
       D:Documents and SettingsDummy.m2
epositoryjunitjunit3.8.1junit-3.8.1.jar
[INFO] Artifact=log4j 
       D:Documents and SettingsDummy.m2
epositorylog4jlog4j1.2.15log4j-1.2.15.jar
[INFO] messaggio=Ciao mondo!!!
[INFO] Class instance class webprova.Prova is ok!!
[INFO] Class instance class org.apache.log4j.Logger is ok!!
[INFO] output file:D:progettimavenPluginwokring3.5webprova	arget
[INFO] ------------------------------------------------------------------------

E il file dummyplugin.txt nella cartella di output.

Conclusioni

Nel corso dell’articolo è stato realizzato Dummy, un plug-in la cui finalità era presentare alcuni aspetti basilari per la realizzazione di un plug-in per Maven. Si è visto come ricevere dei parametri in ingresso, come visualizzare dei messaggi mediante log e come recuperare le dipendenze definite per un progetto. Si è visto inoltre come caricare le classi del progetto al fine poter disporre da plugin delle stesse. Nell’ambito di un progetto che seguo, ho utilizzato le nozioni esposte in questo articolo per scrivere un plug-in che analizza le classi di un progetto al fine ricavare le dipendenze tra di esse. Per chi volesse iniziare a scrivere plug-in per Maven si consiglia di proseguire con la lettura di [6].

In allegato a questo articolo sono stati messi i sorgenti del plug-in dummy e del progetto webprova.

Riferimenti

[1] Maven

http://maven.apache.org/

[2] Eclipse

http://www.eclipse.org/

[3] Eclipse plug-in for Maven

http://maven.apache.org/eclipse-plugin.html

[4] Mojo API specification

http://maven.apache.org/developers/mojo-api-specification.html

[5] Maven properties

http://www.sonatype.com/books/mvnref-book/reference/resource-filtering-sect-properties.html

[4] Martin Fowler: The New Methodology

http://maven.apache.org/guides/plugin/guide-java-plugin-development.html

[6] Plug-in Developers Centre

http://maven.apache.org/plugin-developers/index.html

Facebook
Twitter
LinkedIn
Avatar

Francesco Benincasa

Ha iniziato il cammino dello sviluppatore con i linguaggi Pascal, COBOL, C/C++, Visual Basic. In seguito, ha intrapreso il sentiero del web in ASP. Ha conseguito la laurea in Ingegneria Informatica all‘università di Trieste nel 2002. Dal 2000 lavora principalmente in Java. Oggi si occupa di progettazione e sviluppo di architetture web su piattaforma Java. Si interessa anche di .NET e di grafica 3D.

Francesco Benincasa

Francesco Benincasa

Ha iniziato il cammino dello sviluppatore con i linguaggi Pascal, COBOL, C/C++, Visual Basic. In seguito, ha intrapreso il sentiero del web in ASP. Ha conseguito la laurea in Ingegneria Informatica all‘università di Trieste nel 2002. Dal 2000 lavora principalmente in Java. Oggi si occupa di progettazione e sviluppo di architetture web su piattaforma Java. Si interessa anche di .NET e di grafica 3D.
Tutti gli articoli
Nello stesso numero
Loading...

Better Software 2010

Resoconto di una conferenza eclettica

GraniteDS: Flex incontra Java

III parte: Introduciamo il framework Tide

Realizziamo un Web Service con Spring-WS

IV parte: Endpoint del servizio e routing del payload

Professional Open Source: porting di webapp GWT in portlet Liferay

II parte: Concludiamo il porting in Liferay

Mokabyte

MokaByte è una rivista online nata nel 1996, dedicata alla comunità degli sviluppatori java.
La rivista tratta di vari argomenti, tra cui architetture enterprise e integrazione, metodologie di sviluppo lean/agile e aspetti sociali e culturali del web.

Imola Informatica

MokaByte è un marchio registrato da:
Imola Informatica S.P.A.
Via Selice 66/a 40026 Imola (BO)
C.F. e Iscriz. Registro imprese BO 03351570373
P.I. 00614381200
Cap. Soc. euro 100.000,00 i.v.

Privacy | Cookie Policy

Contatti

Contattaci tramite la nostra pagina contatti, oppure scrivendo a redazione@mokabyte.it

Seguici sui social

Facebook Linkedin Rss
Imola Informatica
Mokabyte