Etude de cas PLM - torguet.nettorguet.net/cours/PLM/EtudeDeCasPLM.pdf · Etude de cas PLM Patrice...
Transcript of Etude de cas PLM - torguet.nettorguet.net/cours/PLM/EtudeDeCasPLM.pdf · Etude de cas PLM Patrice...
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
� 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 � 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