Toutes vos classes pour cet exercice doivent être dans le package fr.uge.poo.ducks.
Attention à ne pas modifier les packages des classes fournies. Java se base sur le nom complet des classes (package+nom de la classe).
Cet exercice est une introduction très rapide à la classe ServiceLoader
qui permet d'aller charger dans des jars
des classes qui implémentent une interface donnée.
Pour illustrer, nous allons considérer un exemple simple.
fr.uge.poo.ducks.Duck.java
donne l'interface simplifiée d'un canard. fr.uge.poo.ducks.Duck
. fr.uge.poo.ducks.Duck
.
Les jars ont été construits de manière à signaler à Java qu'ils fournissent des implémentations de l'interface fr.uge.poo.ducks.Duck
. La classe ServiceLoader
permet alors de récupérer les classes fournies par les jars (si ils sont dans le classpath) comme suit:
ServiceLoader<Duck> loader = ServiceLoader.load(fr.uge.poo.ducks.Duck.class); for(Duck duck : loader) { ... }
Ecrire une classe DuckFarm
dont le main va charger les différents canards et afficher leur cri. Il faudra rajouter les jars dans le classpath de votre projet.
Sous Eclipse, il faut aller dans Project>Properties>Java Build Path puis sélectionner classpath et ajouter "External jar". Sous IntelliJ, il faut aller dans File>Project Structure>Librairies et cliquer sur + pour ajouter le jar.
Une fois les jars ajoutés au classpath, vous devriez avoir un affichage du type:
RubberDuck[Anonymous] refuses to quack. RegularDuck[Anonymous] says quack.
L'ordre n'est pas garanti.
L'approche précédente présente deux problèmes:
ServiceLoader
crée un objet de chaque classe mais pas plus. Il est possible de créer plusieurs objets de chaque classe en utilisant serviceLoader.stream
qui renvoie un stream de Provider
pour l'interface Duck
. En appellant plusieurs fois provider.get
, on peut créer plusieurs objets.
Nous voudrions pouvoir créer plusieurs canards et les nommer. L'idée est de ne plus fournir un canard mais une usine à canard c'est à dire un objet capable de créer des canards à volonté à partir de leur nom.
Pour cela, on introduit l'interface fr.uge.poo.ducks.DuckFactory.java.
package fr.uge.poo.ducks; public interface DuckFactory { Duck withName(String name); }
On vous fournit trois jars RegularDuckFactory.jar,RubberDuckFactory.jar et Surprise.jar qui fournissent des classes pour l'interface fr.uge.poo.ducks.DuckFactory.java
.
Ecrire une classe DuckFarmBetter
qui charge toutes les implémentations disponibles de DuckFactory
et pour chacune crée 3 canards nommés Fifi, Riri et Loulou puis affiche leur cri.
Un jar
est juste une archive comme un fichier ZIP. Il contient des fichiers compilés .class et des fichiers textes de configuration.
On peut décompresser le jar RegularDuckFactory.jar avec la commande suivante:
$ jar -xf RegularDuckFactory.jar
Le contenu du jar est le suivant:
|-META-INF/ |-services/ |-fr.uge.poo.ducks.DuckFactory |-fr/ |-uge/ |-poo/ |-ducks/ |-RegularDuck.class |-Duck.class |-RegularDuckFactory.class |-DuckFactory.class
Le jar contient les fichiers compilés des classes RegularDuck
et RegularDuckFactory
et des interfaces Duck
et DuckFactory
. En plus des classes compilées, le jar contient dans le répertoire META-INF/services un fichier nommé fr.uge.poo.ducks.DuckFactory. Ce fichier fr.uge.poo.ducks.DuckFactory n'a qu'une ligne qui est le nom (package+classe) de la classe qui implémente l'interface fr.uge.poo.ducks.DuckFactory. Dans notre cas, c'est fr.uge.poo.ducks.RegularDuckFactory.
Pour créer le jar, on peut rassembler tous les fichiers nécessaires dans un répertoire tmp avec la bonne structure et créer le jar avec la commande:
$ jar cvf RegularDuckFactory.jar -C tmp/ .
Comme ce procédé est un peu long et pénible, nous avons utilisé un script makeSPIJar.sh.
Toutes vos classes pour cet exercice doivent être dans le package fr.uge.poo.paint.ex8. Recopiez vos classes de l'exercice 7 dans ce nouveau package.
Comme la librairie CoolGraphics
est un plagiat de la librairie SimpleGraphics
, la société EvilCorp a des problèmes juridiques. Il vous faut trouver une solution pour pouvoir distribuer votre application sans la librairie CoolGraphics
. Cependant on voudrait que l'utilisateur puisse rajouter cette librairie en téléchargeant un jar sur le site d'EvilCorp mais sans toucher au code de votre application.
L'idée est de fournir le code de la libraire CoolGraphics
, de votre adaptateur pour cette librairie, ... dans un jar. L'application Paint
utilisera un ServiceLoader
dans votre application pour charger les classes de ce jar si il est présent.
Quelle interface doit fournir votre jar ?
Construisez un jar pour la librairie CoolGraphics
et modifier votre application Paint
pour qu'elle charge CoolGraphics
si disponible, et utilise SimpleGraphics
sinon.
Pour construire votre jar, vous pouvez adapter le script makeSPIJar.sh que nous avons utilisé pour créer le RegularDuckFactory.jar
à l'exercice précédent. Il faut adapter le script.