6.2 Architecture du client
Le client est séparé en deux packages. Un package
est un regroupement logique de classes. Le premier package est un package
outil, il permet de manipuler des
FIG. 6.3 - Schéma simplifié du diagramme des
classes des outils
plages, des listes de plages, de faire les communications
avec le réseau et possède un modèle d'interface graphique.
Le deuxième package est constitué des classes permettant de faire
l'applet: c'est le package ayant permis de faire l'interface graphique ou
interface homme/machine (IHM).
6.2.1 Outils pour l'interface
La première classe, BlockAdresses, permet de
gérer les plages sous formes CIDR ou non. Elle permet d'obtenir
l'adresse réseau d'un sous réseau, de récupérer le
masque, d'obtenir l'adresse de broadcast, d'obtenir les adresses suivantes,
précédentes, parentes... Cette classe était
nécessaire pour faciliter grandement le développement futur. Pour
le schéma simplifier du diagramme des classes, voir la figure 6.2.1 page
34.
La classe SsReseau hérite de cette classe et a une
association avec une autre classe: InfoSsReseau, qui stocke les informations
sur un sous réseau: le propriétaire, le registrar, la
description, l'identifiant. L'identifiant est une chaîne de
caractère inexploitable par le client. En effet, le client ne peut que
stocker cette valeur et la récupérer mais ne connaît pas la
manière de l'utiliser. Cet identifiant est utilisé par le serveur
qui fournit la bonne adresse (URL) pour ouvrir le document Web sur un
établissement particulier. Cette méthode a été
utilisée pour éviter de devoir changer le code du client (parser
l'identifiant notamment) si l'établissement a été
changé de base de données ou si le stockage est différent
(«éclatement» de la base de données sur plusieurs
serveurs). De plus, ce n'est pas à lui de savoir comment sont
gérés les sous réseaux, si ils proviennent bien d'une base
de données plutôt que de fichiers ou d'une requête whois.
Deux classes pour gérer les listes. Une classe Liste
qui définit les méthodes se positionnant au premier ou au dernier
élément, et des méthodes pour savoir si le suivant et le
précédent existent. Ensuite une autre classe ListeSsReseaux qui
per-
met d'ajouter un sous réseau et de
récupérer le suivant ou le précédent sous
réseau. Pourquoi avoir séparé en deux classes? Tout
simplement, la première permet de définir une classe
générique, ne connaissant pas ce qu'il y a l'intérieur de
la liste mais où toutes les méthodes sont mutuellement exclusives
l'une de l'autre (méthodes «synchronized» : on ne peut pas
appeler une deuxième méthode tant que la première
méthode appelée n'a pas libéré le verrou en se
terminant). Ensuite, une classe ListeSsReseaux spécialise cette classe
pour ajouter ou récupérer un et un seul type d'objet: chaque
classe sera alors spécifique à un objet, ce qui permet de ne pas
rencontrer de problème lors de la récupération des
informations. De même, chaque méthode sera de type
«synchronized». Ceci parce que les communications sont
gérées de telles manières que des données peuvent
arrivées alors que l'interface homme-machine récupère les
données précédentes en même temps et il peut y avoir
conflit. Mais ce sera expliqué plus en profondeur plus loin. Ces deux
classes peuvent générer une exception PlusRienException, lorsque
l'on essaye d'accéder au delà des bornes de la liste.
La classe Communication permet de gérer les
communications avec le serveur. Cette classe hérite de Thread. En effet,
étant donné que les requêtes whois peuvent prendre beaucoup
de temps, il se peut que cela bloque l'affichage pendant un long moment, sans
qu'il ne soit possible d'arrêter la requête. En procédant
comme cela, il est très simple de l'arrêter car on lance le
thread, on attend les résultats, lorsque les résultats arrivent
au fur et à mesure, un autre thread peut les afficher, puis si le temps
est trop important pour l'utilisateur, il peut faire une autre requête,
avec ou sans l'arrêt du thread courant. Ceci aurait été
beaucoup plus compliqué à mettre en oeuvre sans les threads, il
aurait fallu pour cela utiliser des méthodes de lecture non bloquantes
sur la socket et s'assurer à intervalle régulier de la
réception des informations. Cependant, ceci aurait du être fait du
côté de l'IHM, ce qui était inacceptable. Comme cela le
problème est simplifié et le codage de l'IHM n'a pas à se
soucier de ce cas de figure: les données lui arrivent automatiquement
par un processus décrit ci après.
Une classe permet de modéliser l'arrivée
d'informations de la part de la communication: la classe ThreadIHM. Cette
classe modélise en fait un «écouteur de communication».
En effet, lors de la création d'un objet de la classe Communication, il
faut lui passer comme argument un objet d'une classe héritant de
ThreadIHM pour que les méthodes de cet objet soient appelées par
l'objet de la classe Communication. Certaines méthodes abstraites de la
classe ThreadIHM doivent être écrites pour que la méthode
soit appelée. Ces méthodes sont:
- aAppeler: qui prend comme paramètre un sous
réseau. Cette méthode est appelée lorsqu'une nouvelle
donnée arrive depuis le réseau.
- erreur: qui prend comme paramètre un message
d'erreur. Cette méthode est appelée lorsqu'une erreur de
communication est arrivée.
- terminer: cette méthode est appelée
lorsque la communication est terminée et que toutes les données
sont parvenues.
D'autres méthodes ne sont pas modifiables, ne peuvent pas
être ré-écrites lors de l'héritage : ceci permet
l'intégrité et l'assurance que les messages d'erreur et les
données parviendront à l'objet correspondant. Il
s'agit de run et de arrete qui per-met d'arrêter la
communication des deux côtés (côté client et
côté serveur).
Cette méthode de communication et d'utilisation avec
l'interface graphique ou textuelle permet une mise en place aisée : il
suffit de créer une classe héritant de ThreadIHM et
implémentant les méthodes déclarées comme
abstraites; créer un objet de la classe Communication avec comme
paramètre un objet de la classe précédente et
appelée l'une des méthodes de Communication. Ce processus permet
de ne pas geler l'IHM, car d'autres choses (réaction lors d'un clique
sur un bouton, entré de nouveaux paramètres, ...) peuvent
être effectuées en même temps que l'interrogation du serveur
à lieu et l'on peut facilement arrêter la communication en cours.
Notamment, les interfaces graphiques se prêtent très bien à
ce type de méthodes.
6.2.2 Interface Graphique
L'interface graphique est composée de plusieurs parties
: la visualisation des sous réseaux, la partie recherche de plages
libres, la partie recherche selon un filtre et la partie navigation. Les
communications entre ces trois parties, par appel de méthodes,
s'effectuent selon le schéma 6.2.2 à la page 37.
Pour le schéma simplifié du diagramme des
classes, voir la figure 6.2.2 page 38.
Au début, la partie visualisation était
composée de boutons (JButton du package javax.swing). Cependant, de
nombreux problèmes de placement de ces boutons étaient
présents : malgré l'utilisation d'un outil de placement de
composants graphiques sous la forme d'un tableau ( GridBagLayout) avec hauteur
et largeur définie (grâce à GridBagConstraints), les
composants ne se plaçaient pas exactement comme il leur était
imposé. En fait, leur position x et y était correct, cependant,
leur taille, surtout la largeur, ne restait pas constante. Certains boutons se
superposaient et lors d'affichage de nombreux boutons, cela devenait
inutilisable. De plus, les performances d'affichage n'étaient pas
suffisantes. Sous les conseils du responsable, il a été choisi de
dessiner directement les cases et non d'ajouter des boutons. Cela s'est
avéré être un très bon choix, les performances ont
été bien meilleures et le placement correspondait exactement
à ce qui était demandé. De plus, la modification a
été très rapide à effectuer, il a suffit de ne pas
faire hériter notre bouton de JButton et de faire une méthode
dessine, les coordonnées, la taille (hauteur et largeur)
étant calculer précédemment.
Chaque partie de l'interface utilisant la classe Communication
est un thread, ce qui fait qu'il y a deux threads par partie négociant
avec le serveur, un pour un objet de la classe Communication, un pour le
composant effectuant l'affichage, soit au total et au maximum six threads
simultanés. Il est spécifié «au maximum» car il
se peut et ce sera la majorité du temps, qu'il n'y ait que deux threads
exécutés en même temps. Cependant, des tests ont
été effectués pour lancer les six threads en même
temps, les arrêter et les relancer de nombreuses fois sans que cela ne
pose le moindre problème. Il faut aussi noter que si la visualisation
est lancée et
FIG. 6.4 - Schéma de représentation des
communications dans l'interface graphique. La classe ThreadIHM a
été ajouté pour simplifier la compréhension
que l'utilisateur essaye de naviguer ou sélectionne une
plage trouvée lors d'une recherche alors que le thread de visualisation
n'est pas terminé (autrement dit: la communication entre la
visualisation et le serveur n'est pas finie), les threads sont automatiquement
arrêtés et la visualisation est relancée sur cette nouvelle
information. Ce qui fait que chaque thread est indépendant des autres
mais le thread visualisation peut être interrompu par l'utilisateur
lorsqu'il sélectionne une plage trouvée par une recherche ou
naviguer ou qu'il souhaite sélectionner une plage dans l'historique.
|