46
Etude de cas PLM Patrice TORGUET IRIT Université Paul Sabatier

Etude de cas PLM - torguet.nettorguet.net/cours/PLM/EtudeDeCasPLM.pdf · Etude de cas PLM Patrice TORGUET! ... But de l’étude de cas : ... Socket d’écoute sur le port 1234 (même

Embed Size (px)

Citation preview

Etude de cas PLM Patrice TORGUET

IRIT Université Paul Sabatier

Plan �  Exemple PLM

�  Répartition avec Sockets

�  Répartition avec RMI

�  Répartition avec CORBA

�  Répartition avec JMS

�  Répartition avec Java EE

�  Améliorations

Exemple orienté PLM �  Base de donnée très simple permettant de gérer

un ensemble de produits avec plusieurs versions et des fichiers CAO (CatProduct) pour chaque version

�  But de l’étude de cas : rendre accessible cette base de donnée via plusieurs technologies réseaux

�  2 projets Netbeans téléchargeables ici :

http://torguet.net/cours/PLM/

Exemple orienté PLM

Exemple orienté PLM

�  Utilisation de l’API JDBC : Java DataBase Connectivity

�  Package java.sql et utilisation du SGBD H2

�  PLMJDBC.java

�  Méthodes �  boolean creerVersion(String nom, String nomFichier)

�  boolean changerFichier(String nom, int version, String nomFichier)

�  String dernierFichier(String nom)

�  ArrayList<Historique> historique(String nom)

Sockets

�  Application Client/Serveur multi-protocole transport �  TCP/UDP

�  Quelque soit le protocole le traitement est le même

�  Les résultats sont partagés (si on fait une modif en TCP, elle est visible en UDP et vice versa)

Fonctionnement Client TCP

1

Client TCP 2

Client UDP 1

Client UDP 2

Serveur ���multi-protocole

Sock Ecoute

Sock Service

Sock Client

Sock DG

Th1

Th2

Th Ecoute

Th DG

ProtoPLM

�  But : traiter les requêtes indépendamment du protocole transport (TCP ou UDP)

�  Utilise PLMJDBC

�  En fonction des types de requêtes appelle la bonne méthode de PLMJDBC

�  Méthode synchronized pour les threads

ProtoPLM

�  Le serveur implante les requêtes suivantes :

�  CREER nom nomFichier crée une nouvelle version du produit en précisant le nom du fichier

�  CHANGER nom version nomFichier remplace le nom du fichier pour une version actuelle du produit

�  RECUP_DERNIER nom demande le nom du fichier de la dernière version du produit

�  RECUP_HISTO nom demande un historique de toutes les versions du produit

Gestion Proto

�  Le client recevra les réponses du serveur sous la forme suivante : �  OK commande

informe le client que la commande s'est correctement déroulée.

�  ERREUR raison la raison de l'échec de la commande sous forme de chaîne de caractères.

�  DERNIER <nomFichier> ���envoie au client le nom du fichier de la dernière version

�  HISTO historique envoie au client une chaîne de caractère résumant l’historique du produit

Serveur �  Version gérant TCP et UDP

�  Partage d’un objet ProtoPLM �  Modif TCP visible dans UDP et vice-versa

�  Tous les threads TCP utilisent le même objet ProtoPLM

�  Partie UDP gérée par un thread

Serveur �  Version TCP en multi-thread

�  Socket d’écoute sur le port 1234 (même port que UDP)

�  Boucle infinie faisant des accept + création de thread

�  Threads gérant chacun un socket de service

�  Tous les threads partagent le même ProtoPLM

Serveur �  Thread service TCP

�  Attention : méthode run() sans paramètre.

�  On doit travailler avec le socket de service et le ProtoPLM

�  Récupération du socket de service (un par thread)

�  Et du ProtoPLM (partagé par tous les threads – d’où le synchronized) dans le constructeur

�  On recopie les références dans des attributs pour pouvoir les utiliser dans la méthode run()

Serveur �  Thread service TCP

�  Méthode run()

�  Construit des flux de haut niveau permettant la lecture et l’écriture de String (requête et réponse)

�  Lecture : BufferedReader

�  Reader alors que les sockets renvoient un InputStream (uniquement lecture d’octets)

�  Utilisation de InputStreamReader qui transforme un InputStream en Reader

�  BufferedReader permet de faire des readLine()

�  Ecriture : PrintStream

�  C’est le type de System.out

�  PrintStream permet de faire des println()

�  Appel de la méthode traiter pour “transformer” une requête en réponse

Serveur �  Thread gérant UDP

�  Constructeur qui récupère le ProtoPLM (partagé avec la partie TCP)

�  On recopie la référence dans un attribut pour l’utiliser dans la méthode run()

Serveur �  Thread gérant UDP

�  DatagramSocket utilisant le même numéro de port que la partie TCP (il y a autant de ports TCP que de ports UDP)

�  DatagramPacket utilisant un tampon de 1024 octets (suffisamment long pour contenir requêtes et réponses a priori mais attention à l’historique)

�  On reçoit un datagramme UDP

�  Les données vont dans le tampon, l’adresse IP et le port distants dans des attributs (getAddress() et getPort())

�  On construit une String à partir de la partie du tampon correspondant à la réception (de 0 jusqu’à getLength() )

�  On appelle la méthode traiter (comme pour TCP)

�  On transforme la réponse en tableau d’octets

�  On place ce tableau d’octet dans le DatagramPacket reçu

�  On renvoie à l’expéditeur (son addresse et son port sont dans les attributs)

Client TCP �  Créer un socket client en précisant le nom de la machine

serveur (ou son adresse IP) et le numéro de port

�  Construire des flux de haut niveau (BufferedReader et PrintStream) comme côté serveur

�  Envoyer une requête (ici en dur mais on pourrait demander à l’utilisateur de la taper, ou faire un menu texte, une interface graphique...)

�  Attendre la réponse puis l’afficher

�  Puis fermer la connexion (on aurait pû envoyer plusieurs requêtes avant)

Client UDP �  On crée un socket datagramme en laissant le système choisir le port

local

�  On récupère l’adresse IP du serveur

�  On construit un DatagramPacket qui va porter la requête (ici en dur mais...) en précisant l’adresse IP et le port du serveur

�  On envoit le DatagramPacket au serveur

�  On construit un DatagramPacket pour recevoir la réponse (avec un tampon suffisamment grand)

�  On attend la réponse

�  On reconstruit une String avec la partie du tampon qui correspond à ce qu’on a reçu

�  On affiche la chaîne de caractères

RMI

RMI

RMI �  Interface PLM dérivant de java.rmi.Remote

�  Reprend les méthodes de PLMJDBC et les rend accessibles à distance

�  Ne pas oublier les “throws RemoteException” qui sont générés côté client en cas de problème dû à RMI

RMI �  Classe d’implantation

�  Dérive de la classe UnicastRemoteObject (gestion des références distantes : souche et squellette)

�  Implante l’interface précédente

�  Méthodes qui délèguent au méthodes identiques de PLMJDBC

RMI �  Programme principal de mise en place

�  Création du RMI Registry sur le port standard : 1099

�  Création d’un objet serveur et nommage

RMI �  Programme client

�  Recherche de la souche dans le RMI Registry distant

�  Transtypage vers le type de l’interface (on ne connait pas le type réel de l’objet souche)

�  Appels de méthodes distantes comme si c’était des méthodes locales

RMI

�  Attention à la sérialisation ! �  Tous les objets doivent pouvoir être sérialisés

�  String, Date et ArrayList le sont en standard

�  Historique doit être déclaré comme “implements Serializable”

CORBA �  Contrat IDL

�  Reprise du type Historique comme une struct IDL

�  Type sequence correspondant à notre ArrayList

�  Ajout d’une exception (problème des null qui ne sont pas portables)

�  Interface correspondant à l’interface RMI

�  Génération des classes Java

CORBA �  Création du servant

�  Ici approche par héritage de PLMPOA

�  Utilisation d’un PLMJDBC

�  Méthodes déléguant au PLMJDBC

�  Attention aux null, on doit à la place lancerdes exceptions

�  Attention à Historique : on doit utiliser la classe générée. Donc on recrée l’historique complet en tant que tableau.

CORBA

�  Serveur

�  Utilisation de l’ORB de Java ou de Visibroker

�  Pour l’ORB Java on peut vouloir démarrer le NameService (ORBD) automatiquement

CORBA �  Etapes de mise en place côté Serveur

�  Initialisation de l’ORB

�  Récupération du POA Racine

�  Création servant

�  Activation de l’objet dans le POA

�  Activation du POA

�  Gestion du nom et de l’IOR

�  Attente de la fin de l’exécution de l’ORB

CORBA

�  Etapes de mise en place côté Client �  Initialisation de l’ORB

�  Gestion du nom et de l’IOR

�  Transtypage vers le type de l’interface générée

�  Appel des méthodes distantes au travers de l’ORB

JMS �  Utilisation d’OpenJMS

�  Implémentation libre et assez facile à mettre en place

�  Outil d’administration permettant de créer des outils de communication (Files ou Sujets de discussion)

�  Ici on va créer une file PLM qui servira pour faire passer les messages requêtes du client au serveur

JMS �  Programme Serveur

�  Création d’un InitialContext JNDI à partir de propriétés permettant de préciser la classe de la factory et la machine et le port du JMSProvider

�  Recherche de la file et de la Connection Factory

�  Création de la connexion, de la session, d’un consommateur de message utilisant la file

�  Création d’un producteur de message ne précisant pas la file utilisée (passage par des files temporaires)

JMS �  Programme Serveur (suite)

�  Utilisation d’un PLMJDBC

�  Boucle d’attente/réception de message

�  Transtypage vers MapMessage (utilisé pour les requêtes par le client)

�  Récupération du JMSType des messages et des paramètres

�  Appel de la bonne méthode du PLMJDBC

�  Création de la réponse et envoie via la file temporaire précisée en JMSReplyTo

�  Note : on peut envoyer un ArrayList<Historique> dans un ObjectMessage grâce à la sérialisation

JMS �  Programme Client

�  Création d’un InitialContext JNDI à partir de propriétés permettant de préciser la classe de la factory et la machine et le port du JMSProvider

�  Recherche de la file nommée et de la Connection Factory

�  Création de la connexion, de la session

�  Création d’une file temporaire pour recevoir les réponses

�  Création d’un consommateur de message utilisant la file temporaire

�  Création d’un producteur de message utilisant la file nommée

JMS �  Programme Client (suite)

�  Création des requêtes de type MapMessage précisant le bon JMSType et les paramètres

�  Ajout de la file temporaire en JMSReplyTo

�  Envoi du message et attente de la réponse

�  Extraction des informations dans la réponse après transtypages

�  On peut récupérer n’importe quel objet sérialisable via un ObjectMessage

Java EE

�  Création d’un projet de type Application d’Entreprise avec Netbeans

�  Création d’un sous-projet EJB (on peut aussi avec des projets Web liés pour le client par exemple)

�  2 types d’EJB utilisés ici �  Entité : ORM

�  Session : Métier

�  Un Web Service

Java EE

�  EJB Entité créé automatiquement depuis une base de donnée

�  Utilisation de JavaDB (derby) déjà inclu avec Netbeans Entreprise

�  Création base de donnée

�  Exécution script SQL

�  Configuration dans le serveur d’entreprise Glassfish

Java EE

�  Code généré qui gère l’association entre les objets et le modèle relationnel

�  Attributs correspondant aux colonnes de la table

�  Génération de requêtes nommées

�  Ajout d’une requête nommée (Plm.findByNomVersion) pour sélectionner les lignes en précisant le nom du produit et la version d’un produit

Java EE

�  EJB Session de type Stateless avec une interface Locale (pourrait être Remote)

�  Code métier de l’application utilisant l’EJB entity et un EntityManager pour la persistence

�  Injection de ressources : ici l’EntityManager créé et géré par le conteneur d’EJBs

Java EE

�  Le code métier utilise les requêtes nommées et des requêtes supplémentaires en précisant les paramètres

�  Pour simplifier on renvoit une chaine de caractères pour l’historique (on aurait pû renvoyer du texte formatté en JSON pour une utilisation facilité dans un client JavaScript)

Java EE

�  NetBeans permet de générer automatiquement un Web Service depuis un EJB Session en rendant ses méthodes accessibles à distance

�  On pourra noter ici aussi de l’injection de ressource pour lier le WS avec l’EJB Session

Java EE

�  Configuration de Glassfish �  Démarrage de JavaDB (onglet Services)

�  Création base de donnée “PLM” sur JavaDB

�  Exécution du script ...\DUPLM2\PLMdb.sql

�  Démarrage de Glassfish

�  Lancement Console d’administration de Glassfish

Java EE

�  Configuration de Glassfish �  Création d’un Connexion Pool JDBC

�  Nommé par exemple PLMPool

�  Resource Type : javax.sql.DataSource

�  Database Driver Vendor : Derby

�  Next

�  Additional Properties

�  DatabaseName : PLM

�  Password : APP

Java EE

�  Configuration de Glassfish �  Création d’une Ressource JDBC

�  Nommée jdbc/PLM

�  Pool Name : PLMPool

�  Déployer l’application en cliquant sur “Run” après un clic droit sur le projet DUPLM2-ejb

�  Tester le WS en cliquant sur “Test Web Service” après un clic droit sur le Web Service (dans le dossier Web Services du projet)

Améliorations de

l’application �  On se propose d’ajouter les améliorations

suivantes : �  A chaque version d’un produit est associé un

responsable ; �  Un produit est constitué d’éléments qui sont

eux-mêmes des produits ; �  A un produit correspond un nombre quelconque

d’instances dont certaines sont vendues et pour lesquelles on doit associer un client et des informations d’usure pour la maintenance

Améliorations de

l’application �  Choisissez une version de l’application et

implantez ces diverses améliorations en suivant la méthodologie suivante :

�  Rétro-conception de l’application avec UML

�  Conception de l’amélioration avec UML

�  Codage, déploiement et tests de l’amélioration