CSC 4509 – Algorithmique et communications des applications réparties

Portail informatique

Devoir maison : Étape 1

  • mise en place du projet avec Maven et explications des procédures avec un exemple utilisant JAVA NIO pour la manipulation de fichiers.

Cette étape est réalisable à la suite de la séance 1 et devrait être réalisée, si possible avant, ou tout au moins pas très longtemps après, la séance 2.

Prérequis pour la réalisation de cette étape :

Mise en place du projet

Maven est un outil développé par Apache Software Foundation pour la gestion complète du cycle de vie d'un projet JAVA, depuis sa compilation (en important automatiquement toutes les bibliothèques nécessaires), jusqu'à son déploiement. Pour ce cours, les projets sont fournis avec le fichier de configuration Maven déjà écrit, et sa lecture peut sembler un peu ardue. Pour vous familiariser avec cet outil, vous devez prendre en charge l'écriture du fichier qui gère votre devoir. Toutes les subtilités que permet cet outil ne seront pas nécessaires, mais vous devez utiliser les notions principales.

Maven repose sur l'idée que les développeurs respectent des conventions. Tant que ces conventions sont respectées, Maven sait ce qu'il doit faire, quand il doit le faire et où trouver ce dont il a besoin, et ceci sans que vous ayez à le lui dire. Respecter ces conventions évite trop de configuration.

Mise en place de l'aborescence Maven

La première des conventions à respecter est l'aborescence de votre projet. Allez dans le répertoire racine de votre projet et commencez par créer les sous-répertoires suivants :

  • ./src : tout ce que vous écrivez (code du programme, tests du programme, etc.) doit être sous ce répertoire, et tout ce qui apparaît sous ce répertoire est de votre fait. Si vous respectez les conventions, Maven n'ira jamais y écrire quoique ce soit ;
  • ./src/main : il contient le code de votre programme et les éventuelles ressources utilisées (images, fichiers css, etc.) ;
  • ./src/main/java : il contient le code JAVA de votre programme (et donc pour ce projet, tout le code applicatif [c'est-à-dire hors code pour les tests]) ;
  • ./src/main/resources : il contient des fichiers de resources (nous nous en servons pour le fichier de configuration de log4j2). ;
  • ./src/test : il contient le code et les ressources de vos tests ;
  • ./src/test/java : il contient le code JAVA de vos tests ;
Lors des commandes mvn, Maven crée le répertoire « ./target » dans lequel il place tous les fichiers qu'il génère.

Création du fichier minimal de configuration de Maven

Même si le respect des conventions précédentes évitent beaucoup de configuration, il faut quand même fournir des informations à Maven. Ce fichier de configuration n'est pas un fichier de commandes (comme pourrait l'être un fichier Makefile), mais un fichier de déclarations. Ces déclarations donnent à Maven les données utiles aux commandes mvn. Ces informations sont fournies dans un fichier XML : « pom.xml » pour Project Object Model.

Voici la version minimale de ce fichier :

  • la balise <project> englobe la configuration de votre projet ;
  • la balise <modelVersion> indique le format du fichier « pom.xml ». Seule la version « 4.0.0 » est reconnue par la version actuelle de Maven ;
  • la balise <groupId> indique l'organisme auteur du projet. L'usage est d'utiliser le nom du site de l'organisme écrit dans l'ordre du plus global au plus local, avec la syntaxe d'un nom de paquetage ;
  • la balise <artifactId> indique le nom de projet. Adaptez en mettant vos noms et prénoms ;
  • la balise <version> indique la version du projet. Une version en développement doit être sufixée par « -SNAPSHOT ».

La configuration par défaut de Maven est prévue pour des projets anciens et utilise par défaut la version 1.5 de JAVA. Pour ce module, nous utilisons des éléments postérieurs à la version 17. Ce changement de configuration se fait dans une section <properties> qui permet d'indiquer des propriétés d'éléments utilisés dans le projet. Dans cette nouvelle version du fichier « pom.xml », nous utilisons la version connue par votre système d'exploitation et nous explicitons l'encodage des fichiers pour éviter d'utiliser l'encodage implicite dépendant de la plateforme de compilation.

Placez ce fichier « pom.xml » à la racine de votre projet, et tapez dans un terminal la commande « mvn install ». Maven déroule toutes les étapes de la compilation à l'installation en créant tous ses fichiers dans un répertoire « target » placé à côté du répertoire « src ». Comme votre projet est vide (ne possède pas de code JAVA), le contenu du répertoire target n'est pas décrit ici.

Premiers usages de Maven et écriture d'un programme avec JAVA NIO

Écriture d'une première classe : Bonjour

Passez sous Eclipse pour écrire une première classe pour ce projet. Sélectionnez l'option de menu « File > Import > Maven > Existing Maven Projects », et validez. Dans la fenêtre du choix du répertoire, sélectionnez le répertoire racine de votre projet (là où se trouve le fichier « pom.xml ») et validez. Votre projet est maintenant sous Eclipse et doit porter le nom que vous avez mis dans la balise <artifactId> du fichier « pom.xml ».

Sous Eclipse, dans le répertoire « src/main/java », créez un paquetage « tsp.csc4509.dm.appli », puis créez dedans la classe « Bonjour ». Et ensuite, écrivez dans cette classe un programme qui affiche « Bonjour untel », où « untel » est le contenu du premier argument du « main ». Eclipse gère ce programme, et avec les options par défaut, l'a compilé sans vous le dire. Vous pouvez le lancer à travers Eclipse. Mais lors du module CSC4509, vous devez lancer plusieurs fois le même programme en même temps, avec des arguments différents, et parfois, vous devez les arrêter abruptement (les interrompre avant leur fin, pour les relancer suite à une erreur ou un changement de version). L'interface d'Eclipse est mal conçue pour ces usages. Des shell-scripts lancés depuis un terminal sont finalement la façon la plus efficace de gérer ce genre de cas. Comme Maven place tout à des endroits bien précis, il est simple d'écrire ces scripts pour vos projets.

Prenons l'exemple de l'application « tsp.csc4509.dm.appli.Bonjour » que vous venez d'écrire. Même si Eclipse l'a déjà compilé, demandez à Maven de le refaire : dans le répertoire racine de votre projet, tapez dans un terminal la commande « mvn install », que vous aviez déjà utilisée avec le projet vide. Lorsque votre projet sera plus riche, cette commande fera bien plus que la compilation des classes.

Maintenant que le projet contient une classe, Maven a placé sa version compilée dans le répertoire « target/classes/tsp/csc4509/dm/appli/ ». Écrivez un script (par exemple « Bonjour.sh ») pour lancer cette application :

#!/bin/bash PROJECTROOT=le_repertoire_racine_de_votre_projet export CLASSPATH=$PROJECTROOT/target/classes java tsp.csc4509.dm.appli.Bonjour $* exit $?

Créez le répertoire « scripts » à la racine de votre projet, et placez-y le script « Bonjour.sh ». Après lui avoir donné les droits d'exécution, il suffit de taper dans un terminal une commande qui ressemble à « ./scripts/Bonjour.sh Monde ».

Écriture d'une seconde classe : FichierNio

Créez la classe « tsp.csc4509.dm.appli.FichierNio ». Elle contient le code d'une application qui écrit les N premiers entiers dans un fichier pour ensuite les relire en les plaçant dans une liste.

  1. Écrivez la méthode writeValues :


    Astuce : la méthode write de cannaux JAVA NIO ne fonctionne pas avec des IntBuffer. Il faut donc allouer un ByteBuffer dimensionné avec la taille « nombre d'entiers * Integer.BYTES » et utiliser la méthode ByteBuffer::putInt().

  2. Écrivez la méthode readValues :


  3. Écrivez la méthode principale main qui :
    • utilise deux arguments : l'argument args[0] contient le nom du fichier où sont écrits puis lus les entiers, et l'argument args[1] contient la limite (non incluse) des entiers à écrire ;
    • ouvre en écriture le fichier et utilise la méthode writeValues pour y écrire les entiers entre 0 et limite (non incluse) ;
    • ouvre en lecture le fichier et utilise la méthode readValues pour charger les entiers dans une List (par exemple, la classe concrète ArrayList) ;
    • affiche le contenu de cette List après la lecture.
  4. Dans le répertoire « scripts », ajoutez un script qui permet d'exécuter cette nouvelle application.

Écriture d'une classe de test

Ajout de JUnit à la configuration de Maven

Lorsque nous écrivons une méthode, il faut aussi écrire des tests unitaires qui l'accompagnent. La bibliothèque JUnit est dédiée à cette tâche. Il faut donc l'installer sur votre ordinateur. Une des tâches de Maven est de gérer toutes les bibliothèques dont vous avez besoin pour un projet. Pour ce faire, nous enrichissons la configuration Maven pour utiliser JUnit lors de la phase de test.

La section « <dependencies> » est apparue. Tout au long du projet, nous ajoutons dans cette section les bibliothèques utilisées. Cette section peut contenir autant de dépendences que nécessaire. Chaque nouvelle dépendance est placée entre les balises « <dependency> » « </dependency> ».

Entre ces balises <dependency> on trouve généralement trois sous-balises :

  • <groupeId> : l'organisme émetteur de la bibliothèque ;
  • <artifactId> : le nom de la bibliothèque ;
  • <version> : le numéro de version de la bibliothèque.

Lorsque vous exécutez une commande Maven, vous lui fixez un objectif (en anglais, goal). Par exemple la commande « mvn install » a pour objectif l'installation. En outre, si vous regardez la trace d'exécution, vous devez voir qu'avant d'atteindre ce but, Maven en a atteint d'autres : la compilation, puis les tests, puis le packagaging, et ensuite seulement, l'installation. Les principaux objectifs d'un projet JAVA avec Maven sont :

  1. compile ;
  2. test ;
  3. package ;
  4. install ;
  5. deploy.

Pour information, il est possible d'en ajouter d'autres, comme l'objectif « site » que vous utiliserez plus tard dans ce module.

Les bibliothèques utilisées pour un projet ne sont pas forcément utiles pour tous les objectifs. Par exemple, la bibliothèque JUnit n'a à être ni utilisée dans la compilation du code applicatif ni déployée chez les utilisateurs du projet. Donc, nous réduisons la portée (en anglais, scope) de la dépendance à JUnit avec une balise « <scope> ». Par conséquent, ajoutez « <scope>test</scope> » dans la section <dependency> pour la dépendance de JUnit, qui n'est utilisée que pour la compilation et l'exécution des tests.

La section « <build> » est aussi apparue. Jusqu'à présent, nous avons laissé Maven utiliser ses règles par défaut pour tout construire. Pour la construction des tests, Maven utilise le plugin « surefire ». Actuellement, la configuration par défaut de Maven est prévue pour l'usage de JUnit 4, alors qui nous utilisons JUnit 5. Pour que Maven déclenche bien nos tests, il faut lui demander d'utiliser une version de plugin « surefire » plus récente que la version par défaut. Nous sommes donc obligés d'ajouter la section pour configurer ce plugin. Notez que pour le projet que vous utiliserez dans la seconde partie de CSC4509, nous utiliserons cette section pour configurer plus finement les tests unitaires.

Enfin, pour que Maven prenne en compte les modifications de la configuration, demandez à effacer tout ce qu'il a généré : commande « mvn clean » , et re-exécutez l'installation : commande « mvn install ». Comme il est possible de donner plusieurs buts à Maven en une seul commande, nous utiliserons dans la suite la commande « mvn clean install ».

Comprendre le format d'une classe de Test

Une classe de test contient des méthodes qui vont être appelées par JUnit. Pour que JUnit puisse les utiliser, elles doivent respecter le format suivant:

Les principales annotations sont:

  • @Test (import org.junit.jupiter.api.Test): à placer devant chacune des méthodes de test unitaire ;
  • @BeforeEach (import org.junit.jupiter.api.BeforeEach): à placer devant une méthode qui sera appelée avant chaque méthode de test unitaire (si on a besoin de remettre en place une configuration avant chaque test) ;
  • @AfterEach (import org.junit.jupiter.api.AfterEach): à placer devant une méthode qui sera appelée après chaque méthode de test unitaire (si on a besoin de faire une terminaison après chaque test) ;
  • @BeforeAll (import org.junit.jupiter.api.BeforeAll): à placer devant une méthode (static) qui sera appelée avant tous les tests (si on besoin de faire une préparation avant les tests) ;
  • @AfterAll (import org.junit.jupiter.api.AfterAll): à placer devant une méthode (static) qui sera appelée après tous les tests (si on besoin de faire une action pour clore les tests) ;
  • @Disabled (import org.junit.jupiter.api.Disabled) à placer devant une annotation @Test pour désactiver le test .

L'exemple de code ci dessus, produit donc les affichages suivants:

Par défaut les tests s'exécutent dans l'ordre alphabétique des noms des méthodes, mais il est possible d'en changer l'ordre avec l'annotation "@Order".

Ajout d'une classe de test au projet

Par convention, nous plaçons les classes des tests dans le répertoire « src/test/java » et avec un nom de paquetage identique aux classes à tester. Donc, sous Eclipse, dans le répertoire « src/test/java », créez le paquetage « tsp.csc4509.dm.appli ». Téléchargez la classe TestFichierNio et placez-la dans ce paquetage.

Créez le répertoire « data » à la racine de votre projet. La classe des tests qui vous est donnée utilise ce répertoire. Dans « data », placez tous les fichiers de données utilisés par vos tests. Téléchargez le fichier entiers0-9.data et placez-le dans le répertoire « data ». Ajouter ce fichier, ainsi que tous les futurs fichiers de données de test à votre dépôt Git.

Lancez la commande « mvn clean install » pour réinstaller le projet. Comme nous l'avons vu plus haut, Maven passe par une phase de tests avant d'arriver à l'installation. Si votre mèthode writeValues a été écrite correctement, l'installation a dû arriver à son terme, mais cette fois-ci en exécutant un test.

Ajoutez une nouvelle méthode de test testReadValues() à la classe tsp.csc4509.dm.appli.TestFichier pour réaliser les tests unitaires de la méthode readValues() de votre projet. Vérifiez que votre projet passe bien les tests.

 


$Date: 2021-04-27 00:22:04 +0200 (mar. 27 avril 2021) $