4 nov. 2021 15:32:02 Thomas Dumont avatar

Fonctionnement de lutece-maven-plugin

Un portail web lutece est une webapp java EE. Le contenu de cette webapp (JSP, classes java, templates HTML, etc.) provient directement du Core Lutèce (obligatoire) et de plugins (facultatifs). L'assemblage d'une webapp à partir du Core et de la liste de plugins est faite avec l'outil Maven.

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 Lutèce s'appuie sur :

  • deux POMs parents regroupant les configurations par défaut des projets Lutèce :
    • lutece-global-pom pour les projets de type "lutece-core" ou "lutece-plugin".
    • lutece-site-pom pour les projets de type "lutece-site".
  • un plugin Maven lutece-maven-plugin spécifique à Lutèce ressemblant au maven-war-plugin.

Assemblage d'une webapp lutece

L'architecture du projet Lutèce 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

Lutece-maven-plugin s'inspire de maven-war-plugin pour réaliser les opérations suivantes :

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

Ressemblances entre lutece-maven-plugin et maven-war-plugin

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

  • Il gère deux dossiers :
    • src/ pour le code à compiler,
    • 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...), 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", 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.

Différences entre lutece-maven-plugin et maven-war-plugin

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 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épendance de type lutece-core
  • dépendances de type lutece-plugin
  • dossier "webapp" de l'artifact courant
  • defaultConfDirectory
  • localConfDirectory

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

Important 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.

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

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 :

$ mvn lutece:exploded

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

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 :

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

Par convention, les modules sont définis dans un profile "multi-project" en rajoutant ceci au pom.xml du projet multi module :

<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

Afin d'éviter de recompiler et de redéployer tous les modules du projet, on a la possibilité de le faire seulement sur un seul module. Pour cela, il faut se placer directement dans le répertoire du module au niveau de son pom.xml et lancer la commande suivante :

$ mvn lutece:exploded -DtestWebappDirectory="../target/lutece"