Blog Zenika

#CodeTheWorld

Java

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.

  1. group = ‘com.zenika.wicket’
  2. version = ‘1.0-SNAPSHOT’
  3. 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.

  1. usePlugin(‘war’)
  2. usePlugin(‘jetty’)

Gestion des dépendances

Ensuite nous déclarons les librairies nécessaires

  1. dependencies {
  2. addFlatDirResolver(‘lib’, « $rootDir/lib »)
  3. compile « :wicket:1.3.5 »,
  4. « :wicket-extensions:1.3.5 »,
  5. « :wicket-datetime:1.3.5 »,
  6. « :scriptaculous:1.3 »,
  7. « :yav:1.0 »,
  8. « :slf4j-log4j12:1.4.2 »,
  9. « :log4j:1.2.14 »,
  10. « :joda-time:1.4 »,
  11. « :slf4j-api:1.4.2 »,« :slf4j-log4j12:1.4.2 »
  12. testCompile « :junit:3.8.2 »
  13. }

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.

  1. addFlatDirResolver(‘lib’, « $rootDir/lib »)

Dans notre cas, le pattern de récupération est ‘artifactrevision.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)

  1. targetCompatibility = ‘1.5’
  2. 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)

  1. createTask(‘resources’,overwrite:true){
  2. ant{
  3. echo(message:‘Copy HTML resources’)
  4. copy(todir:‘build/classes’){
  5. fileset(dir:‘src/main/java’){
  6. exclude (name:‘**/*.java’)
  7. }
  8. }
  9. }
  10. }

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

  1. createTask(‘wrapper’, type: Wrapper).configure {
  2. gradleVersion = ‘0.5.2’
  3. archiveBase = Wrapper.PathBase.PROJECT
  4. archivePath = ‘wrapper’
  5. jarPath = archivePath
  6. }

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.

Une réflexion sur “Utiliser le builder Gradle pour vos applications Wicket

  • Franck Vallée

    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

    Répondre

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

En savoir plus sur Blog Zenika

Abonnez-vous pour poursuivre la lecture et avoir accès à l’ensemble des archives.

Continue reading