projet composants logiciels - e
Transcription
projet composants logiciels - e
IUT Vélizy PROJET COMPOSANTS LOGICIELS Licence SIL Université de Versailles Saint Quentin SUJET Introduction. Il s’agit d’une application qui réalise le travail d'une caisse enregistreuse dans des salons de coiffure appartenant à une chaîne de franchises. Les services proposés aux clients de ces salons sont bien sûr des coupes de cheveux. Les coupes sont adaptées à chaque type de client, femme, homme et enfant. Une coupe peut être accompagnée de services supplémentaires comme par exemple un shampoing, une couleur, un brushing ou un soin capillaire. enregistrer une vente <<include>> <<include>> s'authentifier consulter le journal des ventes employé d'un salon de coiffure Ce sont les employés des salons qui utilisent l'application. Celle-ci doit leur faciliter le travail en proposant une interface Homme-machine conviviale et simple. Les cas d'utilisation recensés par l'équipe projet ont permis d'identifier un seul type d'utilisateur, les employés des salons de coiffure. Les cas d'utilisations sont «enregistrer une vente » et « consulter le journal des ventes ». L'application n'est utilisable qu'après authentification de son utilisateur. Celle-ci repose sur un identifiant et un mot de passe. Les deux cas d'utilisation nécessitant une identification, le cas d'utilisation « s'authentifier » a été conceptualisé afin de factoriser dans un seul cas cette fonctionnalité. Il est relié aux deux autres par une relation de type include. Le premier cas, l'enregistrement d'une vente, permet de choisir un type de coupe de cheveux et les services supplémentaires éventuels que le client a demandés. Le second cas, le journal des ventes, mémorise l'ensemble des ventes avec le détail des coupes et suppléments vendus aux clients (désignation et montant). JJLC 1/10 LICENCE SIL Contraintes non fonctionnelles. L'application est une application Web hébergée au siège de la chaîne sur un serveur d'applications. Elle est développée avec la plateforme JAVA EE1. C'est à dire avec le langage JAVA et les technologies SERVLET et JSP mais structurées par le cadriciel (framework) standard JSF2 qui en représente une couche d'abstraction. Docker Docker Client navigateur Internet Application Web HTTP JDBC déployée dans Tomcat Derby mode client-serveur RMI Docker JDBC Application EJB déployée dans Wildfly Les informations produites par l'application sont stockées dans une base de données relationnelle. Cette base de données sert de source de données à plusieurs applications de l'entreprise, c'est pourquoi elle doit fonctionner en mode client-serveur. L'éditeur de la base de données choisie est la fondation APACHE et son produit logiciel qui est libre3, est le SGBDR4 DERBY. Le serveur d'application retenu pour héberger l'application est le produit logiciel libre TOMCAT, lui-même appartenant au projet Jakarta de la fondation APACHE. Il s'agit d'un serveur HTTP capable d'exécuter des applications JAVA EE WEB. Ses clients sont les ordinateurs de type caisse enregistreuse présents dans les salons de coiffure. L'application est accessible via un navigateur internet (browser). Le système d'authentification permet de contrôler et sécuriser l'accès à l'application. Il est hébergé sur un serveur JAVA EE de type full profile, c'est à dire capable d'exécuter des composants lourds de type EJB (Enterprise JavaBean). Le serveur retenu est le produit logiciel libre WILDFLY de l'éditeur JBoss appartenant à la société REDHAT. Chacun des trois serveurs, d'applications et de données, est déployé dans un conteneur léger de type LXC avec la solution d'isolation Docker. Les images des conteneurs sont disponibles à partir de DockerHub et sont respectivement lecoz/derbysiolapie:latest, lecoz/tomcatsiolapie:latest et lecoz/wildflysiolapie:latest. 1 2 3 JAVA EE : JAVA Enterprise Edition JSF : JAVA SERVER FACES Logiciel libre et Open source 4 SGBDR : système de Gestion de Base de Données Relationnelle (RDBMS en anglais) JJLC 2/10 LICENCE SIL Le modèle métier. L'originalité de l'application est qu'elle repose sur un modèle métier persistant structuré grâce aux patrons de conception5 Décorateur et Monteur (Builder). Le patron de conception Décorateur s'adapte bien aux modèles contenant des objets qui représentent un système d'information de base, ici les coupes de cheveux pour femme, pour enfant et pour homme, et d'autres objets qui eux représentent un système d'information optionnel ou complémentaire à celui de base, ici les services supplémentaires (couleur, brushing, soins, etc). Le patron de conception Monteur permet de déléguer à une structure de classes la responsabilité d'ordonnancer les tâches à réaliser afin de construire un graphe d'objets complexe. Dans le cas présent celui de construire une structure de décoration. Le modèle métier a vocation à être persistant. La technologie employée à cette fin est la couche de persistance standard du langage JAVA : JPA (JAVA PERSISTENCE API). Le produit logiciel libre utilisé pour implémenter cette couche est HIBERNATE6. <<entity>> + Service -désignation : String -tarif : double 1 -service +detail() : String +montant() : double + Coupe + Supplément +detail() : String +montant() : double + Coupe Femme +detail() : String +montant() : double + Coupe Enfant + Brushing + Pas de Coupe + Couleur + Coupe Homme + Shampoing + Soin Capillaire La solution de persistance du modèle décorateur et donc sa correspondance (mapping) au niveau de la base de données relationnelle est implémentée par une seule table (solution union). Donc une seule table pour toute la dérivation comprenant les classes Service, Coupe, Supplément, CoupeHomme, CoupeFemme, CoupeEnfant, PasDeCoupe, Brushing, Couleur, Shampoing et Soin. Il est possible qu'une cliente ou qu'un client ne désire pas de coupe mais ne veuille qu'un ou plusieurs services de type supplément. Par exemple un simple brushing. C'est ce qui explique la présence de la classe PasDeCoupe. 5 Design Pattern 6 Hibernate est un des leaders pour les solutions de persistance des objets Java JJLC 3/10 LICENCE SIL Le patron de conception Monteur est composé d'une interface et de deux classes responsables de la construction de la structure d'objets de la décoration, c'est à dire d'une liste chaînée. Le Monteur ou Builder est d'ailleurs conçu pour faciliter la création de graphes d'objets complexes. Dans le cas d'une vente d'un service de coiffure, la construction doit absolument commencer par la création d'un objet concret de type CoupeFemme, CoupeEnfant, CoupeHomme ou PasDeCoupe et être « décoré » par zéro ou plusieurs suppléments. La classe DirecteurDuMontage représente l'interface du patron de conception. C'est à elle que s'adresse les objets consommateurs du montage. + MonteurDeService + DirecteurDuMontage 1 +dirigerLaConstruction() : void -monteur +construire() : void +getResultat() : Service 1 + Service -résultat structure décorateur décrite dans l'autre diagramme de classe + MonteurDeServiceImpl +construire() : void La classe MonteurDeServiceImpl implémente l'interface MonteurDeService. C'est elle qui a la responsabilité de concrètement construire la structure d'objet représentant la Décoration. Code source de la classe Monteur : public class MonteurDeServiceImpl extends MonteurDeService { private Map<String, Class> services = new Hashtable<String, Class>(); public MonteurDeServiceImpl() { super(); initialisation(); } public Service creationService(List<String > choixServices) throws Exception { Service vente = creationServiceCoupe(choixServices.get(0)); for(int i = 1; i < choixServices.size(); i++) vente = creationServiceSupplement(choixServices.get(i), vente); instanciation par réflexion return vente; } public Service creationServiceCoupe(String typeService) throws Exception { return (Service) services.get(typeService).newInstance(); } public Service creationServiceSupplement(String typeService, Service service) throws Exception { return (Service) services.get(typeService).getConstructor(Service.class).newInstance(service); } private void initialisation() { services.put("CF", CoupeFemme.class); services.put("CH", CoupeHomme.class); services.put("PC", PasDeCoupe.class); services.put("CO", Couleur.class); services.put("BR", Brushing.class); services.put("SC", SoinCapillaire.class); services.put("SH", Shampoing.class); } } JJLC 4/10 LICENCE SIL L'application Web. L'application « enregistrer une vente » est structurée grâce au cadriciel JSF. Elle doit proposer une interface graphique Homme-Machine (IHM) composée de deux listes déroulantes pour en faciliter l'utilisation. La première liste propose les services ou formules de base (coupes de cheveux). La seconde liste propose les suppléments (couleur, brushing, shampoing et soin capillaire). La première liste est une liste à choix unique alors que la seconde est une liste à choix multiple. Un bouton permet à l'utilisateur de valider la vente et donc l'enregistrement des services vendus. Les listes de choix sont initialisées statistiquement dans la page JSF. Elles correspondent à un composant géré (ManagedBean) avec un cycle de vie égal à celui de la requête HTTP (request scope). Ainsi, à chaque fois qu'une vente est validée les objets qui correspondent à chacun des choix sont instanciés et mis en relation en conformité avec le patron de conception Décorateur qui structure le modèle grâce aux objets qui implémentent le patron Monteur. Puis le tout est rendu persistant dans la base de données grâce à l'interface de programmation (API) JSF de la couche de persistance. Classes et pages de l'application WEB : 1 <<jsf>> + login.xhtml <<managedbean>> <<request>> + ComposantAuthentificateur <<Remote>> + Authentificateur +authentifier(login : String,password : String) : UtilisateurDTO +authentifier() : String + UtilisateurDTO 2 3 4 <<jsf>> + menu.xhtml <<jsf>> + vente.xhtml <<managedbean>> <<application>> + FournisseurDeGerantDePersistance <<managedbean>> <<request>> + ComposantVente +fournir() : EntityManager +enregistrer() : void <<jsf>> + journal.xhtml <<managedbean>> <<request>> + ComposantJournal + ValueObject +initialisation() : void La page d'accueil de l'application (login.xhtml) est celle qui permet à l'utilisateur de s'authentifier. Si l'authentification réussit, la navigation propose le menu général (menu.xhtml). Selon le choix de l'utilisateur la navigation propose la page d'enregistrement d'une vente (vente.xhtml) ou celle qui permet de consulter le journal comptable des ventes (journal.xhtml). C'est le composant JAVA JSF ComposantAuthentificateur qui interagit avec la page login.xhtml. Il délègue au service distant implémenté par un composant EJB, l'authentification de l'utilisateur. Le composant JAVA JSF ComposantVente, quant à lui, interagit avec la page vente.xhtml. Il a la responsabilité d'enregistrer la vente. Le composant JAVA JSF ComposantJournal interagit avec la page journal.xhtml. Il a la responsabilité de créer un objet valeur (ValueObject) contenant la liste des ventes utilisée par la page journal.xhtml. JJLC 5/10 LICENCE SIL L'application EJB. L'accès à l'application est soumise à authentification. Celle-ci est implémentée par un composant distribué de type EJB Session Stateless et par un composant persistant de type EJB Entity. Ils ont pour nom respectif : AuthentificateurEJB et Utilisateur. Le composant distribué AuthentificateurEJB implémente la méthode authentifier() qui contrôle le login et le password saisis dans l'interface Homme-machine. Chaque utilisateur correspond à un nuplet dans la table UTILSATEUR de la base de données. Un objet de type Data Transfer Object (DTO) permet de communiquer la réussite ou l'échec de l'authentification à l'application WEB. Le diagramme de classe UML détaille ci-dessous les composants qui interagissent pour implémenter le cas d'utilisation « s'authentifier ». <<interface>> + Authentificateur +authentifier(login : String,password : String) : UtilisateurDTO <<interface>> + java.io.Serializable <<realize>> <<realize>> + UtilisateurDTO <<EJB Stateless>> <<Remote>> + AuthentificateurEJB +authentifier(login : String,password : String) : UtilisateurDTO -nom : String -prénom : String -message : String <<EJB Entity>> + Utilisateur -nom : String -prénom : String -login : String -password : String L'objet UtilisateurDTO est transmis via le protocole JAVA RMI à l'application WEB à l'issue du processus d'authentification. Si l'authentification a réussi alors l'objet DTO contient le nom, le prénom de l'utilisateur et le message a pour contenu « Bienvenue ». En cas d'échec seul le message est renseigné avec le contenu « Echec ». Cet objet doit implémenter l'interface java.io.Serializable afin de pouvoir être encodé (Marshalling) et décodé (UnMarshalling) dans un format lui permettant d'être acheminé par le réseau du serveur WILDFLY au serveur TOMCAT. JJLC 6/10 LICENCE SIL L'interface Homme-Machine. L'interface de l'application est très simple. Elle doit permettre aux utilisateurs de réaliser une vente très rapidement. L'utilisateur une fois authentifié arrive sur un menu qui propose les choix qui correspondent aux deux cas d'utilisation : enregistrer une vente et journal des ventes. L'application enregistrer une vente propose le choix de la coupe (Enfant, Femme, Homme, Pas de Coupe) grâce à une liste déroulante à choix unique. comportement AJAX Le choix des suppléments est quant à lui réalisé avec l'aide d'une liste déroulante à choix multiple. Un bouton permet de valider la vente. Un autre de retourner au menu principal. Après le choix des services et le clic du bouton « enregistrer » il est possible de prévoir un comportement de type AJAX qui affiche le résumé de la vente : détail des services et total à régler par le client. Extrait de la classe ComposantVente en interaction avec la page vente.xhtml : @ManagedBean(name = "vente") @RequestScoped public class ComposantVente { private String coupe; private List<String> supplements = new ArrayList<String>(); @ManagedProperty(value = "#{fournisseur}") private FournisseurDeGerantDePersistance fournisseur; public void enregistrer(AjaxBehaviorEvent event) throws Exception { ... Extrait de la page vente.xhtml : <h:outputLabel>Coupe :</h:outputLabel> <h:selectOneListbox value="#{vente.coupe}" size="1"> <f:ajax event="click" execute="@form" render="resume" listener="#{vente.raz}"></f:ajax> <f:selectItem itemValue="CF" itemLabel="coupe femme" /> <f:selectItem itemValue="CH" itemLabel="coupe homme" /> <f:selectItem itemValue="PC" itemLabel="pas de coupe" /> </h:selectOneListbox> <h:outputLabel>Suppléments :</h:outputLabel> <h:selectManyListbox value="#{vente.supplements}" size="4"> <f:selectItem itemValue="BR" itemLabel="brushing" /> <f:selectItem itemValue="CO" itemLabel="couleur" /> <f:selectItem itemValue="SH" itemLabel="shampoing" /> <f:selectItem itemValue="SC" itemLabel="soin capillaire" /> </h:selectManyListbox> JJLC 7/10 LICENCE SIL La base de données. Le schéma relationnel est composé de la table SERVICE. Elle est la résultante de la correspondance objet-relationnel (mapping O-R). Cette correspondance est basée sur la solution UNION. C'est à dire une seule table pour implémenter une dérivation (interfaces, classes). Le patron de conception (Design pattern) Décorateur est basé sur un système de relation réflexive ce qui explique la présence de la colonne SERVICE_FK. Celle-ci est une clé étrangère qui pointe, qui référence la clé primaire de la même table. Tous les services de type supplément sont chaînés entre eux et à une coupe ou non coupe via cette clé étrangère. Pour restaurer les objets de type Service, la requête SQL ne doit sélectionner que les objets périphériques de chaque décoration. Le patron de conception décorateur est un système qui crée un amas d'objets dans une architecture qui ressemble à celle des oignons. Avec un cœur, un noyau entouré, décoré par une succession de pelures d'oignon. La structure globale est donc une liste chaînée de n-uplets dont il faut retrouver le dernier maillon pour restaurer l'ensemble des objets appartenant à une décoration. Schéma relationnel de la base de données lien réflexif de la décoration La requête SQL est la suivante : SELECT * FROM SERVICE WHERE IDSERVICE NOT IN (SELECT IDSERVICE FROM SERVICE WHERE IDSERVICE IN (SELECT SERVICE_FK FROM SERVICE)) Elle sélectionne le dernier n-uplet de chaque service vendu (la dernière pelure d'oignon). Celui qui correspond au dernier choix de service : simple coupe ou supplément (dernier décorateur). Ainsi la couche ORM (Object-Relational Mapping) JPA peut restaurer chaque graphe d'objets qui correspond à une vente en partant de l'objet le plus périphérique de la structure de décoration. La clé étrangère permet de traverser tout le graphe. JJLC 8/10 LICENCE SIL ANNEXES Page JSF du menu de l'application : Page JSF du journal des ventes : JJLC 9/10 LICENCE SIL Page JSF de l'authentification : Diagramme de déploiement : serveur physique: 192.168.x.x Docker derby: 172.0.17.2 Docker wildfly: 172.17.0.3 venteDB serveur WILDLFY lien docker SGBDR DERBY authentificationDB authentification JDBC lien docker JDBC lien docker Docker tomcat: 172.17.0.4 RMI JAVA serveur tomcat caise enregistreuse JPA JSF répertoire contenant les bases de données dans le conteneur solution alternative pour rendre persistante la base de données Script de démarrage des conteneurs Docker : #!/bin/bash docker stop $(docker ps -a -q) docker rm $(docker ps -a -q) #docker run -d --name derby -v /home/etudiant/docker/sgbdr:/opt/sgbdr lecoz/derbysiolapie:latest docker run -d --name derby lecoz/derbysiolapie:latest docker run -d --name wildfly --link derby:derby -v /home/etudiant/docker/wildflylogs:/wildfly-8.1.0.Final/standalone/log lecoz/wildflysiolapie:latest docker run -d --name tomcat --link derby:derby --link wildfly:wildfly -v /home/etudiant/docker/tomcatlogs:/apache-tomcat-8.0.15/logs lecoz/tomcatsiolapie:latest JJLC 10/10 LICENCE SIL