Utiliser le builder Gradle pour vos applications Wicket
Dans le billet sur le concours du dévelopement d’une application Web en Wicket, une solution de l’application Zencontact avait été donnée. Cette solution utilise le système de construction Maven. Nombre d’entre vous ne savent pas très bien utiliser Maven, ou n’ont tout simplement pas envie d’installer la très lourde infrastructure Maven.
Maven est un outil de build très populaire et très utilisé. Néanmoins, il souffre de nombreuses lacunes. Il ne s’agit pas de la solution ultime; la preuve avec la naissance de nombreux autres outils de builds après Maven comme Gant, Gradle, Quokka, Kundo, EasyAnt, …
La section suivante présente l’utilisation du builder Gradle sur l’application Web Wicket Zencontact.
Gradle est un système de build innovant. Utilisant une syntaxe Groovy, il est à base de conventions comme dans Maven avec par exemple
- des conventions de répertoires
- des conventions de noms
- des cycles de vie intégrés
- un système de gestion de dépendances avancé
- une gestion des sous modules
Conventions de répertoire
Gradle utilise les mêmes conventions de répertoire que Maven. Dans l’application zencontact :
- les sources Java sont dans ‘src/main/java’,
- les ressources statiques du projet dans ‘src/main/resources’
- les ressources Web du projet dans ‘src/main/weapp’
- les sources Java de tests dans ‘src/test/java’
- …
Conventions de noms
La première partie du script consiste à déclarer l’entité organisationnelle sur laquelle est rattachée le projet Gradle (group), la version du projet et la base des noms des artefacts générés.
-
group = ‘com.zenika.wicket’
-
version = ‘1.0-SNAPSHOT’
-
archivesBaseName=‘zencontact’
Dans cette configuration, l’artefact généré sera nommé ‘zencontact-1.0-SNAPSHOT.war’.
Cycles de vie
Une seconde section consiste à décrire l’utilisation du plugin Gradle ‘war’ mettant à disposition un cycle de vie dédié à la construction d’une archive Web (init, resources, compile, testResources, testCompile, test, archive_war, libs, uploadLibs).
Puis nous déclarons le plugin ‘jetty’ permettant de démarrer le serveur d’application Jetty afin de tester l’application générée.
-
usePlugin(‘war’)
-
usePlugin(‘jetty’)
Gestion des dépendances
Ensuite nous déclarons les librairies nécessaires
-
dependencies {
-
addFlatDirResolver(‘lib’, “$rootDir/lib”)
-
compile “:wicket:1.3.5”,
-
“:wicket-extensions:1.3.5”,
-
“:wicket-datetime:1.3.5”,
-
“:scriptaculous:1.3”,
-
“:yav:1.0”,
-
“:slf4j-log4j12:1.4.2”,
-
“:log4j:1.2.14”,
-
“:joda-time:1.4”,
-
“:slf4j-api:1.4.2”,“:slf4j-log4j12:1.4.2”
-
testCompile “:junit:3.8.2”
-
}
Gradle fournit une déclaration des dépendances du projet dans une syntaxe très simple. Grâce au langage de script Groovy, l’utilisation lourde et non adéquate du langage XML est définitivement proscris; contrairement aux autres outils de build comme Maven. De plus, par l’utilisation d’une DSL Groovy au dessus de l’outil de dépendance Ivy, nous pouvons bénéficier de tous les avantages du plus puissant gestionnaire de dépendance du marché pour déclarer les librairies du projet; et sans l’écriture du descripteur ivy.xml.
Le premier avantage de l’utilisation de Ivy est la capacité d’utiliser son propre resolver, chargé de la récupération des librairies. Dans l’exemple, le resolver va récupérer les librairies dans le repository filesystem ‘lib’, présent à la racine du projet.
-
addFlatDirResolver(‘lib’, “$rootDir/lib”)
Dans notre cas, le pattern de récupération est ‘artifact–revision.ext ‘.
Ce resolver est dans notre cas tout à fait adapté. Il n’y a plus besoin de connexion internet, d
e gérer vos librairies métiers et les librairies techniques dans des repository avec des gestionnaires de repository comme Archiva, Nexus. Mais contrairement à un simple builder comme Ant où toutes vos libraires n’étaient pas classées, ici, nous pouvons clairement spécifier les libraires qui seront utilisées à la compilation, à l’exécution, durant le tests, ….
Remarque: Gradle permet également de ne pas gérer les librairies. Ainsi au lieu de spécifier la section des dépendances, il est possible de simplement spécifier le classpath de compilation.
def wicketJarList = new File("$rootDir/lib").listFiles( [ accept : { File dir , String name -> ( name =~ '.jar$' ).find ( ) } ] as FilenameFilter ) as List compile.unmanagedClasspath = wicketJarList
Spécificité pour notre application Web Wicket
Version de Java
Nous déclarons ensuite que notre application comporte du code source Java 5 et que le résultat de la compilation sera du byte code Java 5 (note : à partir de Gradle 0.6, 1.5 sera la valeur par défaut)
-
targetCompatibility = ‘1.5’
-
sourceCompatibility = ‘1.5’
Copie des ressources HTML
La dernière section du script de build est l’utilisation d’une tâche Ant qui va permettre de copier les ressources HTML Wicket au même niveau que les classes Java compilées (mode par défaut dans Wicket, utilisé dans l’application Zencontact)
-
createTask(‘resources’,overwrite:true){
-
ant{
-
echo(message:‘Copy HTML resources’)
-
copy(todir:‘build/classes’){
-
fileset(dir:‘src/main/java’){
-
exclude (name:‘**/*.java’)
-
}
-
}
-
}
-
}
Remarqe: Gradle permet la réutilisation de toute tâche Ant existante. L’expression est en Groovy, sans XML. Malgré la très grande popularité de Maven 2, Ant reste l’outil de build le plus complet, le plus performant et le plus documenté pour des programmes Java. Avoir à sa disposition, l’ensemble des tâches Ant accessibles, fait de Gradle un système incontournable.
Le wrapper Gradle
Automatiser sa chaîne de construction est une étape essentielle, mais il reste ensuite à la rendre continue en l’adossant à un serveur d’intégration continue. Un des principes de base de l’intégration continue est d’avoir une chaîne de build indépendant de l’infrastructure. Or, à partir du moment où votre script est écrit en Ant ou en Maven, il vous faut l’outil Ant ou l’outil Maven installé sur le serveur d’intégration continue afin d’exécuter le script de build. Vous êtes donc dépendant de l’emplacement de l’outil, de sa version, de ses dépendances extérieures comme les variables d’environnement, les mécanismes de repository pour Maven, ….
Pour builder du script Gradle, vous pouvez installer Gradle et configurer Gradle sur votre serveur d’intégration continue, puis utiliser le plugin Gradle de Hudson. Mais Gradle met gratuitement à disposition son wrapper permettant l’utilisation de Gradle sans avoir l’outil Gradle installé et configuré.
-
createTask(‘wrapper’, type: Wrapper).configure {
-
gradleVersion = ‘0.5.2’
-
archiveBase = Wrapper.PathBase.PROJECT
-
archivePath = ‘wrapper’
-
jarPath = archivePath
-
}
L’invocation de cette tache Gradle génère un fichier gradew pour Unix et gradlew.bat pour Windows, qui appelleront une librairie gradle-wrapper.jar chargé du travail.
Utilisation de l’application Zencontact avec Gradle
Génération de la configuration Eclipse
Tout comme avec Maven, vous pouvez générer la configuration Eclipse (avec les fichiers de configurations WTP dans le cas d’une application Web)
gradle eclipse
ou si vous utilisez le wrapper Gradle
gradlew eclipse
Génération du livrable
La génération de l’archive Web est réalisée par la commande
gradle clean libs
ou si vous utilisez le Gradle wrapper
gradlew clean libs
Gradle exécute un cycle de vie jusqu’à la phase ‘libs’. Il vous suffira ensuite de récupérer l’archive web dans le répertoire ‘build’ et de la déployer dans un container Web.
Test de l’application
Nous vous proposons de tester l’application avec le très léger container Web Jetty. Grâce à la déclaration de l’utilisation du plugin jetty dans le script Gradle, nous pouvons simplement invoquer
gradle jettyRun
ou si vous utilisez le wrapper Gradle
gradlew jettyRun
Téléchargement
Pour tester l’application Wicket zencontact avec Gradle,
- Si vous avez une installation de Gradle déjà existante, vous pouvez télécharger le zip “zencontact-gradle.zip”, extraire le zip dans le répertoire de votre choix et lancer les commandes Gradle.
- Si n’avez pas Gradle installé et que vous ne souhaitez pas l’installer dans le cadre de cette démonstration, télécharger le zip “zencontact-gradle-with-distribution.zip”, extraire le zip dans le répertoire de votre choix et lancer les commandes Gradle wrapper.
Bonjour,
merci pour cet article qui m’a aidé à porter Wicked sur gradle.
Pour s’amender de Ant et être 100% gradle, cette solution fonctionne aussi très bien:
———————————————
plugins {
id “org.gretty” version “2.3.1”
id “java”
id “war”
}
compileJava.options.encoding = ‘UTF-8’
gretty {
httpPort = 8080
debugSuspend = false
servletContainer= “jetty9.4”
}
repositories {
jcenter()
}
dependencies {
// https://mvnrepository.com/artifact/org.apache.wicket/wicket-core
compile group: ‘org.apache.wicket’, name: ‘wicket-core’, version: ‘8.6.1’
// https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-server
compile group: ‘org.eclipse.jetty’, name: ‘jetty-server’, version: ‘9.4.21.v20190926’
// https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-webapp
compile group: ‘org.eclipse.jetty’, name: ‘jetty-webapp’, version: ‘9.4.21.v20190926’
// https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-jmx
compile group: ‘org.eclipse.jetty’, name: ‘jetty-jmx’, version: ‘9.4.21.v20190926’
testCompile group: ‘junit’, name: ‘junit’, version: ‘4.12’
}
import groovy.io.FileType
def htmlMarkupFiles = [];
task collectMarkupFiles {
(new File(“src/main/java”)).eachFileRecurse (FileType.FILES) { file ->
if( file.name.endsWith(‘.html’)) {
htmlMarkupFiles < ” + htmlMarkupFiles
}
task moveMarkupFiles(type: Copy) {
dependsOn collectMarkupFiles
from ‘src/main/java’
include “**/*.html”
into ‘build/classes/java/main’
}
war.dependsOn moveMarkupFiles