May 19, 2017 2:33:52 PM Jon Harper avatar   349    

Construction et assemblage : les builds

Un portail web lutece est une webapp java EE. Le contenu de cette webapp (JSP, classes java, templates HTML, etc.) provient directement du coeur de Lutece (obligatoire) et de plugins (facultatifs). L'assemblage d'une webapp à partir du coeur et de la liste de plugins est faite avec l'outil Maven (https://maven.apache.org/). Avant d'avancer dans la suite de ce chapitre, il est nécessaire de connaitre le fonctionnement de Maven: on peut commencer par la lecture de https://maven.apache.org/users/index.html.

En plus d'une utilisation classique de Maven, l'assemblage de webapps Lutece s'appuie sur:

  • deux POMs parents lutece-global-pom (pour "lutece-core" et "lutece-plugin") et lutece-site-pom (pour "lutece-site"). Ces POMs regroupent les configurations par défaut de projets lutece.
  • un plugin Maven: lutece-maven-plugin. Ce plugin Maven spécifique à Lutece ressemble au maven-war-plugin. Pour comprendre l'utilisation de lutece-maven-plugin, il est recommandé de connaitre maven-war-plugin (https://maven.apache.org/plugins/maven-war-plugin/).

Assemblage d'une webapp lutece

L'architecture du projet lutece est de construire une webapp contenant l'intégralité des fonctionnalités des plugins choisis. Pour ce faire, lutece-core contient les fichiers obligatoires d'une webapp (par exemple WEB-INF/web.xml) et les fichiers qui servent aux fonctionnalités communes à tous les plugins (code java, header et footer des pages html, etc.). Les plugins apportent en plus leurs propres fichiers. De plus, il est parfois nécéssaire pour un site donné de pouvoir modifier certains fichiers présents dans lutece-core ou dans un lutece-plugin (par exemple, modifier un template html). L'objectif principal de l'assemblage d'une webapp lutece est donc de produire les bons fichiers venant des différentes sources à inclure dans la webapp finale. Nous allons voir comment lutece-maven-plugin atteint cet objectif.

Cependant, en dehors de l'assemblage de webapps, l'utilisation de maven permet aussi d'atteindre d'autres objectifs: gérér la compilation et les tests du code, pouvoir publier des artifacts fournissant une fonctionnalité réutilisable, générer la documentation technique (javadoc et Maven Site), etc.

Lien entre lutece-maven-plugin et maven-war-plugin

Maven fournit en standard un plugin qui atteint partiellement l'objectif principal d'assemblage de webapps décrit au paragraphe précédant: maven-war-plugin. Lutece-maven-plugin s'inspire de maven-war-plugin:

  • il compile le code et le place dans le dossier "WEB-INF/classes" de la webapp,
  • il copie les fichiers de la webapp à la racine de la webapp,
  • il copie le contenu (du code compilé ou des fichiers de webapp) des dépendances.

Lutece-maven-plugin ressemble à maven-war-plugin sur les points suivants :

  • Il gère deux dossiers "src" (pour le code à compiler) et "webapp" pour les fichiers à copier dans la webapp. À l'exception de la phase "package" dont on parlera plus bas, il associe les mêmes goals maven aux phases de lifecycle standard (compilation java, tests, déploiement, etc.), ce qui permet de publier normalement des artifacts sur les dépots maven.
  • Il fournit des goals maven pour obtenir la webapp en version "war" ou en version "exploded" ou (pour l'artifact lutece-core uniquement) en version "inplace".
  • Il partage des options de configuration (par exemple finalName et outputDirectory).
  • Il copie les dépendances de type jar dans le dossier WEB-INF/lib d'une webapp complète.
  • Il assemble les webapps en utilisant un concept similaire aux overlays provenant des dépendances.

Lutece-maven-plugin diffère de maven-war-plugin sur les points suivants :

  • le plugin maven-war-plugin utilise une structure "src/main/java" et "src/webapp" pour séparer le code et les fichiers de la webapp. Le plugin lutece-maven-plugin utilise "src/java" et "webapp/".
  • Lutece-maven-plugin n'utilise pas d'artifact de type "war", mais définit plusieurs types d'artifacts maven qui correspondent aux différents éléments de l'architecture lutece: lutece-core, lutece-plugin, lutece-site. Lutece-core et lutece-plugin sont des artifacts qui contiennent des classes java à compiler et des fichiers à copier dans la webapp (à la manière des artifacts de type "war" pour maven-war-plugin). Lutece-site contient uniquement des fichiers à copier dans la webapp, surchargeant ceux provenant d'artifacts lutece-core ou lutece-plugin.
  • Le goal par défaut pour la phase "package" ne produit pas la totalité de la webapp, seulement les fichiers provenant de cet artifact. D'autres goals doivent être invoqués pour obtenir la webapp complète.
  • Contrairement à maven-war-plugin, le concept d'overlay est central et son utilisation systématique dans lutece-maven-plugin: on peut produire une webapp fonctionnelle à partir de n'importe quel type d'artifact lutece-core, lutece-plugin ou lutece-site. La webapp contiendra tous les fichiers provenant de l'artifact et de ses dépendances (classes compilées, fichiers de la webapp).
  • La webapp complète contiendra aussi les fichiers provenant de deux dossiers spéciaux: defaultConfDirectory et localConfDirectory: defaultConfDirectory a pour valeur par défaut "src/conf/default". Lutece-site-pom définit des profils maven qui changent la valeur de defaultConfDirectory à "src/conf/<profile>" : "dev", "rec", "integ", "formation", "preprod", "prod". localConfDirectory a pour valeur par défaut "$HOME/lutece/conf/<artifactId>". Attention, ces fichiers ne proviennent pas d'un artifact maven, ils provoquent donc des assemblages non reproductibles. Il faut les utiliser avec parcimonie.
  • Le reactor maven (mode multi modules) est géré de manière très différente d'un projet maven multi module classique, comme nous le verrons après.

Ces différences permettent d'avoir un système flexible où on peut gérer un grand nombre d'artifacts Maven et donc écrire des composants très modulaires.

Règles d'utilisation de lutece-maven-plugin

Les goals maven utilisés

Nous utiliserons les goals suivants de lutece-maven-plugin :

  • lutece:exploded pour lutece-core et lutece-plugin
  • lutece:site-assembly pour lutece-site

Ordre de surcharge des fichiers

Lutece-maven-plugin utilise de manière pervasive un concept similaire aux overlays de maven-war-plugin. Il est important de savoir dans quel ordre les overlays sont appliqués pour savoir quel fichier est utilisé lorsqu'un fichier est présent dans plusieurs sources. Ceci concerne uniquement les fichiers de la webapp (par exemple dans le dossier "webapp/" d'un lutece-plugin) et un assemblage sans modules maven. L'ordre est :

  • dépendances de type lutece-core ou lutece-plugin
  • dossier "webapp" de l'artifact courant
  • defaultConfDirectory de l'artifact courant
  • localConfDirectory de l'artifact courant

La version utilisée sera celle présente dans le dernier élément de cette liste.

Note: Il n'y a pas d'ordre défini entre les fichiers de deux dépendances, il ne faut donc pas qu'un même fichier existe dans deux dépendances différentes.

Pour l'assemblage en multi-module, l'ordre dépend de l'ordre des artifacts dans le reactor.

Exemples d'utilisation de lutece-maven-plugin

Assemblage d'un lutece-site

L'utilisation la plus simple de lutece-maven-plugin consiste à construire un artifact de type lutece-site sans plugins ni surcharge. Le projet contient alors uniquement un fichier pom.xml à la racine. Ce POM contient:

  • La définition des dépots maven de lutece (pour obtenir le POM parent et le plugin maven)
  • le lien vers le POM parent
  • la dépendance vers l'artifact lutece-core

Maven va télécharger l'artifact lutece-core depuis les dépots et fabriquer la webapp à partir de cet artifact.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/maven-v4_0_0.xsd">
    <parent>
        <artifactId>lutece-site-pom</artifactId>
        <groupId>fr.paris.lutece.tools</groupId>
        <version>2.0.4</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>lutece-example</artifactId>
    <packaging>lutece-site</packaging>
    <name>Lutece example</name>
    <version>1.0.0</version>
    <repositories>
        <repository>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
            <id>luteceSnapshot</id>
            <name>luteceSnapshot</name>
            <url>http://dev.lutece.paris.fr/snapshot_repository</url>
        </repository>
        <repository>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <id>lutece</id>
            <name>luteceRepository</name>
            <url>http://dev.lutece.paris.fr/maven_repository</url>
        </repository>
    </repositories>
    <dependencies>
        <dependency>
            <groupId>fr.paris.lutece</groupId>
            <artifactId>lutece-core</artifactId>
            <version>5.0.0</version>
            <type>lutece-core</type>
        </dependency>
    </dependencies>
</project>

On assemble la webapp en utilisant le goal maven :

$ mvn lutece:site-assembly

Cela produit la webapp en version "war" et "exploded" dans le dossier target:

$ ls target/
lutece-example-1.0.0 lutece-example-1.0.0.war

On peut aussi activer des profils maven lors de ce goal pour utiliser un defaultConfDirectory différent :

$ mvn lutece:site-assembly -P prod

Assemblage d'un lutece-plugin ou de lutece-core

En utilisant le pom.xml du projet qu'on veut assembler, on peut produire une webapp avec la commande :

$ git clone https://github.com/lutece-platform/lutece-core
$ cd lutece-core
$ mvn lutece:exploded

La webapp en version "exploded" est disponible dans le dossier target/lutece/

Utilisation du dépot maven local

Pour simplement propager les changements faits sur un artifact dans une webapp assemblée à partir d'un autre artifact, on peut utiliser le dépot maven local avec la commande maven "install"

$ cd /lutece-core
$ mvn install
$ cd /plugin
$ mvn clean lutece:exploded

Utilisation du Maven Reactor (multi module)

Pour éviter d'avoir à utiliser maven install sur toutes les dépendances, on peut utiliser les modules maven et le reactor. Attention, l'utilisation des modules maven est très particulière avec lutece-maven-plugin et ne s'utilise qu'avec le goal "lutece:exploded". Le mode multi-module assemble une webapp à partir des différents artifacts du reactor dans le dossier "target/lutece" au niveau du pom aggrégateur. On ne peut donc pas utiliser d'artifact lutece-site dans ce genre d'assemblage. Contrairement à une utilisation classique du reactor où les derniers modules produisent les artifacts désirés, lutece-maven-plugin assemble directement tous les modules dans le dossier target du pom aggrégateur au cours du traitement du reactor.

On peut utiliser la structure de projets suivante où on a les différents projets venant de github et le global-pom :

├── lutece-core
├── lutece-search-library-lucene
├── lutece-system-plugin-systeminfo
└── pom.xml

Par convention, on définit des modules lorsque le profile "multi-project" est activé en rajoutant ceci au global-pom pom.xml :

<profiles> 
 <profile> 
  <id>multi-project</id> 
  <modules> 
   <module>lutece-core</module> 
   <module>lutece-system-plugin-systeminfo/</module> 
   <module>lutece-search-library-lucene</module> 
  </modules> 
 </profile> 
</profiles>

On peut ensuite assembler la webapp :

$ mvn lutece:exploded -P multi-project
 [INFO] ------------------------------------------------------------------------
 [INFO] Reactor Summary:
 [INFO]
 [INFO] Lutece global pom ................................. SUCCESS [1.238s]
 [INFO] Lutece Analyzers and indexers ..................... SUCCESS [2.000s]
 [INFO] Lutece ............................................ SUCCESS [4.659s]
 [INFO] Lutece systeminfo plugin .......................... SUCCESS [0.325s]
 [INFO] ------------------------------------------------------------------------
 [INFO] BUILD SUCCESS
 [INFO] ------------------------------------------------------------------------

La webapp est disponible dans le dossier "target/lutece"

Note: attention, à cause des particularités de lutece-maven-plugin en multi-modules, pour nettoyer et recompiler tout en une seule commande on doit utiliser :

$ mvn lutece:clean lutece:exploded -P multi-project