1 I. Bus logiciel ? Mireille Blay-Fornarino Daprès et Sacha Et (cf. références en bas des pages)
2 c Raphaël Marvie Objectifs de ce cours Introduire les principes de base de larchitecture des intergiciels … … via une démarche systématique basée sur le besoin.
3 c Raphaël Marvie Méthodologie suivie pour ce cours Découvrir la structuration dun bus logiciel réparti, en concevant un petit bus simple « from scratch ». Construire un bus logiciel en 10 étapes : Chaque étape est un raffinement de la précédente Etape i + 1 = meilleure structuration de létape i A chaque étape, sil y a lieu, Identification des principaux schémas darchitecture
4 c Raphaël Marvie Etapes 1. Sockets 2. Gestionnaire de connexions 3. Codage et discrimination des requêtes : Gestion de plusieurs requêtes sur une seule connexion 4. Séparation entre Gestionnaire de connexions et servants Réification des services : découplage code métier et technique 5. Proxy : isolation du client Transparence de la répartition « stringware » 6. Décodage et encodage des données 7. Références distantes Abstraction de désignation des sockets 8. Adaptateurs dobjets : plusieurs servants simultanément 9. Gestion dexception, références typées, … 10. Service de désignation Mireille Blay-Fornarino
5 c Raphaël Marvie Les Services Service 1 : Hello world Une méthode hello avec un paramètre de type chaîne et retourne une chaîne : hello, + paramètre Deux méthodes lower et upper qui retournent le paramètre de type chaîne en minuscule ou majuscules Service 2 : Nombres premiers Calcule si un nombre est premier et retourne un booléen Calcule le carré dun nombre passé en paramètre Calcule la division de deux nombres passés en paramètre
6 1. Au début était la socket
7 c Raphaël Marvie Principe Deux programmes écrits en deux classes Java Une pour le serveur Server.java Une pour le client Client.java Dans chaque classe est implémenté Le code fonctionnel : manipulation des chaînes Le code technique : construction / analyse des messages réseau
8 c Raphaël Marvie Architecture version « socket » Client Réseau Serveur
9 c Raphaël Marvie Modélisation des Interactions
10 c Raphaël Marvie Côté serveur Initialisation du réseau Instanciation dune socket serveur Gestion des requêtes Attente de connexion (accept) Initialisation des flux dentrée et de sortie Evaluation des requêtes Lecture de la requête sur le flux dentrée Création de la chaîne à retourner Ecriture de la réponse sur le flux de sortie
11 c Raphaël Marvie Code serveur (i) package step1 ; import java.io.* ; import java.net.* ; public class Server { private ServerSocket asock ; public Server () throws Exception { this.asock = new ServerSocket (12345) ; } public static void main (String args[]) { Server s = new Server () ; s.run () ; }
12 c Raphaël Marvie Code serveur (ii) public void run () throws Exception { while (true) { Socket sock = this.asock.accept () ; BufferedReader in = new BufferedReader (new InputStreamReader(sock.getInputStream ())); DataOutputStream out = new DataOutputStream (sock.getOutputStream ()); String msg = in.readLine () ; String res = "Hello, " + msg + "\n" ; // fonctionnel out.writeBytes (res) ; }
13 c Raphaël Marvie Côté client Initialisation du réseau Instanciation dune socket de communication (connexion implicite) Gestion de léchange réseau Initialisation des flux dentrée et de sortie Demande de service Ecriture de la requête sur le flux de sortie Lecture de la réponse sur le flux entrée Affichage de la chaîne retournée Fermeture de la connexion
14 c Raphaël Marvie Code client (i) package step1 ; import java.io.* ; import java.net.* ; public class Client { private Socket sock ; public Client () throws Exception { this.sock = new Socket ("localhost", 12345) ; } public static void main (String args[]) throws Exception { Client c = new Client () ; c.run (args[0]) ; }
15 c Raphaël Marvie Code client (ii) public void run (String msg) throws Exception { BufferedReader in = new BufferedReader (new InputStreamReader(this.sock.getInputStream ())); DataOutputStream out = new DataOutputStream (this.sock.getOutputStream ()); out.writeBytes (msg + "\n") ; String res = in.readLine () ; System.out.println ("Server replied: " + res) ; this.sock.close(); }
16 c Raphaël Marvie Bénéfices et limitations Bénéfices Invocation dun service distant (hello world) Permet de réaliser des applications client / serveur Limitations Une seule connexion cliente à la fois Beaucoup de code très technique / peu de code métier (40 lignes de code technique pour une ligne de code métier) Un beau plat de spaghettis, difficilement évolutif
17 2. Gestionnaire de connexions
18 c Raphaël Marvie Principe Du côté serveur Etablissement de la connexion par le serveur (accept) La gestion de la connexion est déléguée à un objet Manager qui gère une connexion Du côté client Rien ne change pour le moment Réutilisation du client de létape 1
19 c Raphaël Marvie Architecture version 2 Client Réseau Manager
20 c Raphaël Marvie Interactions version 2
21 c Raphaël Marvie Côté serveur (Serveur) Initialisation De la socket dadministration / serveur Création dun manager de connexions Gestion des requêtes Attente de connexion Délégation au manager
22 c Raphaël Marvie Côté serveur (Manager) Initialisation Rien de spécial Gestion des requêtes Initialisation du flux dentrée et de sortie Evaluation de la requête Lecture de la requête sur le flux entrée Création de la chaîne à retourner Ecriture de la réponse sur le flux de sortie
23 c Raphaël Marvie Code Serveur (i) package step2 ; import java.io.*; import java.net.*; public class Server { private ServerSocket asock ; private Manager mgr ; public Server () throws Exception { this.asock = new ServerSocket (12345) ; this.mgr = new Manager () ; }
24 c Raphaël Marvie Code Serveur (ii) public void run () throws Exception { while (true) { Socket sock = this.asock.accept () ; this.mgr.process (sock) ; } public static void main(String argv[]) throws Exception { Server s = new Server () ; s.run () ; }
25 c Raphaël Marvie Code Manager package step2 ; import java.io.* ; import java.net.* ; public class Manager { public Manager () throws Exception {} public void process (Socket sock) throws Exception { BufferedReader in =... DataOutputStream out =... String msg = in.readLine () ; String res = "Hello, " + msg + "\n" ; out.writeBytes (res) ; }
26 c Raphaël Marvie Bénéfices et limitations Bénéfices Ebauche de structuration Distinction entre établir une connexion et la gérer Limitations Le manager ne sait répondre quà une invocation Le code nest pas encore objet (i.e. le service)
27 3. Décodage des requêtes
28 c Raphaël Marvie Principe Côté serveur Le manager propose plusieurs services Le manager gère plusieurs requêtes par connexion Côté client Utilise les services séquentiellement Réalise plusieurs invocations avec la même connexion
29 c Raphaël Marvie Architecture version 3 Client Réseau Manager
30 c Raphaël Marvie Interactions version 3
31 c Raphaël Marvie Côté serveur Gestion des requêtes par le Manager Initialisation des flux dentrée et de sortie Evaluation de la requête Lecture de la requête sur flux dentrée Décodage de la requête (quel service ?) requête = numéro de service + arguments Evaluation du service demandé Ecriture de la réponse sur flux de sortie
32 c Raphaël Marvie Code Manager (i) public void process (Socket sock) throws Exception { BufferedReader in =... DataOutputStream out =... while (true) { String msg = in.readLine () ; if (msg == null) // end of client connexion break ; String res ; switch (msg.charAt (0)) {
33 c Raphaël Marvie Code Manager (ii) case 0: res = "hello, " + msg.substring (1) + "\n" ; break ; case 1: Res = msg.substring (1).toLowerCase () + "\n" ; break ; case 2: res = msg.substring (1).toUpperCase () + "\n" ; break ; default: res = "Unknow operation requested" ; } out.writeBytes (res) ; }
34 c Raphaël Marvie Côté client Initialisation du réseau Instanciation de la socket de communication Gestion des échanges réseaux Initialisation des flux dentrée et de sortie Demande de service (x3) Requête réseau = numéro de service + arguments Ecriture requête, lecture réponse et affichage Fermeture de la connexion
35 c Raphaël Marvie Code Client (i) public void run (String msg) throws Exception { BufferedReader in =... DataOutputStream out =... String res ; out.writeBytes ("0" + msg + "\n") ; res = in.readLine () ; System.out.println ("Server replied (hello): " + res) ;
36 c Raphaël Marvie Code Client (ii) out.writeBytes ("1" + msg + "\n") ; res = in.readLine () ; System.out.println ("Server replied (lower): " + res) ; out.writeBytes ("2" + msg + "\n") ; res = in.readLine () ; System.out.println ("Server replied (upper): " + res) ; this.sock.close(); }
37 c Raphaël Marvie Bénéfices et limitations Bénéfices Un seul serveur propose plusieurs services Utilisation dune seule connexion par client Limitations Le code du service nest toujours pas objet Le code client est toujours un plat de spaghetti
38 4. Passage à un service objet
39 c Raphaël Marvie Principe Côté serveur Le service est implémenté comme un objet : le Servant Le manager est dédié au réseau décode les requêtes invoque le Servant Côté client Rien ne change
40 c Raphaël Marvie Architecture version 4 Client Réseau Manager Servant
41 c Raphaël Marvie Interactions version 4
42 c Raphaël Marvie Côté serveur Initialisation du Manager dans le serveur Passage du Servant comme paramètre Gestion des requêtes par le Manager Initialisation des flux Evaluation des requêtes lecture et décodage de la requête invocation du Servant écriture de la réponse
43 c Raphaël Marvie Code Server public class Server { private ServerSocket asock ; private Manager mgr ; public Server () throws Exception { this.asock = new ServerSocket (12345) ; this.mgr = new Manager (new Servant ()) ; } // unchanged }
44 c Raphaël Marvie Code Servant public class Servant { public String hello (String msg) { return "hello, " + msg ; } public String lower (String msg) { return msg.toLowerCase () ; } public String upper (String msg) { return msg.toUpperCase () ; }
45 c Raphaël Marvie Code Manager (i) public class Manager { private Servant ref ; public Manager (Servant s) throws Exception { this.ref = s ; } public void process (Socket sock) throws Exception { BufferedReader in =... DataOutputStream out =... while (true) { String msg = in.readLine () ; if (msg == null) // no more to be read break ; String res ; switch (msg.charAt (0)) {
46 c Raphaël Marvie Code Manager (i) case 0: res = this.ref.hello (msg.substring (1)) + "\n" ; break ; case 1: res = this.ref.lower (msg.substring (1)) + "\n" ; break ; case 2: res = this.ref.upper (msg.substring (1)) + "\n" ; break ; default: res = "Unknow operation requested" ; } out.writeBytes (res) ; }
47 c Raphaël Marvie Bénéfices et limitations Bénéfices Découplage complet entre code technique et code métier (côté serveur) Les services sont implantés comme des objets (Servant) Limitations Linterface du service nest pas connue comme telle du client Le code client nest toujours pas objet
48 5. Passage à lobjet du côté client
49 c Raphaël Marvie Principe Côté serveur Définition dun contrat à partager avec le client Le servant implémente le contrat commun Côté client Utilisation dun objet représentant le service : Proxy Même interface que le service Encapsule le code technique de gestion du réseau
50 c Raphaël Marvie Architecture version 5 Proxy Réseau Manager ServantClient Contrat
51 c Raphaël Marvie Interactions version 5
52 c Raphaël Marvie Côté serveur Modifications Définition dun contrat de service Le servant implémente le contrat de service Contrat de service Définit toutes les méthodes accessibles à distance Chaque méthode peut lever une exception liée au réseau
53 c Raphaël Marvie Contrat de service package step5 ; interface Service { public String hello (String msg) throws Exception ; public String lower (String msg) throws Exception ; public String upper (String msg) throws Exception ; }
54 c Raphaël Marvie Modification du Servant public class Servant implements Service { public String hello (String msg) throws Exception { return "hello, " + msg ; } public String lower (String msg) throws Exception { return msg.toLowerCase () ; } public String upper (String msg) throws Exception { return msg.toUpperCase () ; }
55 c Raphaël Marvie Côté client Programme client Instancie un proxy Invocation des méthodes du proxy Mise en oeuvre du Proxy Implémente linterface de contrat Initialise la connexion au serveur Gère toute la partie échanges réseaux
56 c Raphaël Marvie Code du Client public class Client { private Socket sock ; private Service ref ; public Client () throws Exception { this.ref = (Service) new Proxy () ; } public void run (String msg) throws Exception { System.out.println (this.ref.hello (msg)) ; System.out.println (this.ref.lower (msg)) ; System.out.println (this.ref.upper (msg)) ; }
57 c Raphaël Marvie Code du Proxy (i) public class Proxy implements Service { private Socket sock ; private BufferedReader in ; private DataOutputStream out ; public Proxy () throws Exception { this.sock = new Socket ("localhost", 12345) ; this.in =... this.out =... } public String hello (String msg) throws Exception { this.out.writeBytes ("0" + msg + "\n") ; String res = this.in.readLine () ; return res ; }
58 c Raphaël Marvie Code du Proxy (ii) public String lower (String msg) throws Exception { this.out.writeBytes ("1" + msg + "\n") ; String res = this.in.readLine () ; return res ; } public String upper (String msg) throws Exception { this.out.writeBytes ("2" + msg + "\n") ; String res = this.in.readLine () ; return res ; } protected void finalize () throws Throwable { this.sock.close () ; }
59 c Raphaël Marvie Proxy : Bilan Contexte Applications constituées dun ensemble dobjets répartis ; un client accède à des services fournis par un objet pouvant être distant (le servant) Problème Définir un mécanisme daccès qui évite au client Le codage en dur de lemplacement du servant dans son code Une connaissance détaillée des protocoles de communication Propriétés souhaitables Accès efficace et sûr Programmation simple pour le client ; idéalement, pas de différence entre accès local et distant Contraintes Environnement réparti (pas despace unique dadressage) Solutions Utiliser un représentant local du servant sur le site client (isole le client du servant et du système de communication) Garder la même interface pour le représentant et le servant Définir une structure uniforme de représentant pour faciliter sa génération automatique C Sacha Krakowiak
60 c Raphaël Marvie Usage de Proxy C Sacha Krakowiak
61 c Raphaël Marvie Définitions dinterfaces Partie opérationnelle Interface Definition Language (IDL) Pas de standard indépendant IDL CORBA Java et C# définissent leur propre IDL WSDL … Partie contractuelle Plusieurs niveaux de contrats Sur la forme : spécification de types -> conformité syntaxique Sur le comportement (1 méthode) : assertions -> conformité sémantique Sur les interactions entre méthodes : synchronisation Sur les aspects non fonctionnels (performances, etc.) : contrats de QoS C Sacha Krakowiak
62 c Raphaël Marvie Bénéfices et limitations Bénéfices Du point de vue du client la répartition est masquée Le service est vu et manipulé comme un objet local Limitations Comment utiliser des paramètres autres que de type String ? Comment désigner un service distant (sans le coder en dur) ?
63 6. Encodage et décodage des données
64 c Raphaël Marvie Principe Traduction des paramètres Empaquetage : application vers les messages réseau type de base vers représentation chaîne Dépaquetage : messages réseau vers application représentation chaîne vers type de base Opérations de traduction symétriques Serveur : dépaquetage des paramètres, empaquetages des valeurs de retour Client : empaquetage des paramètres, dépaquetages des valeurs de retour
65 c Raphaël Marvie Architecture version 6 Proxy Réseau Manager ServantClient Contrat
66 c Raphaël Marvie Interactions version 6
67 c Raphaël Marvie Côté serveur Modification du contrat de service Offre une opération supplémentaire Calcul du carré dun entier (retourne un entier) Modification de la mise en oeuvre Manager : message réseau supplémentaire et décodage entier Servant : implémentation de la nouvelle méthode
68 c Raphaël Marvie Contrat Service interface Service { public String hello (String msg) throws Exception ; public String lower (String msg) throws Exception ; public String upper (String msg) throws Exception ; public int sqr (int a) throws Exception ; }
69 c Raphaël Marvie Code Manager public void process (Socket sock) throws Exception { // unchanged switch (msg.charAt (0)) { // unchanged for 0-2 case 3: int val = Integer.parseInt (msg.substring (1)) ; res = "" + this.ref.sqr (val) + "\n" ; break ; default: res = "Unknow operation requested" ; } out.writeBytes (res) ; }
70 c Raphaël Marvie Code Servant public class Servant implements Service { // unchanged public int sqr (int val) throws Exception { return val * val ; }
71 c Raphaël Marvie Côté client Modification de la mise en oeuvre Le proxy implémente la nouvelle opération Le programme client utilise la nouvelle opération Mise en oeuvre du Proxy Empaquetage de lentier paramètre dans une chaîne Dépaquetage de lentier contenu dans la chaîne retour
72 c Raphaël Marvie Code Proxy public class Proxy implements Service { // unchanged public int sqr (int val) throws Exception { this.out.writeBytes ("3" + val + "\n") ; String res = this.in.readLine () ; return Integer.parseInt (res) ; }
73 c Raphaël Marvie Code Client public class Client { // unchanged public void run (String msg) throws Exception { System.out.println (this.ref.hello (msg)) ; System.out.println (this.ref.lower (msg)) ; System.out.println (this.ref.upper (msg)) ; int res = this.ref.sqr (123) ; System.out.println (res) ; }
74 c Raphaël Marvie Bénéfices et limitations Bénéfices Utilisation transparente des types de base autres que String Vision objet dune application répartie Limitations Comment désigner un service distant sans le coder en dur ? ( this.sock = new Socket ("localhost", 12345)) Comment écrire un client pouvant utiliser plusieurs services ?
75 7. Notion de référence distante
76 c Raphaël Marvie Principe Désignation dun service distant Equivalent à une référence Java mais en réparti Permet détablir une connexion avec un service Définition dune référence (base) Hôte distant : adresse IP Serveur distant : port IP
77 c Raphaël Marvie Architecture version 7 Proxy Réseau Manager ServantClient Contrat
78 c Raphaël Marvie Interactions version 7
79 c Raphaël Marvie Côté client Fourniture de la référence du serveur Propriété java contenant la référence Référence donnée sous la forme machine:port Ajout dune méthode de gestion des références Analyse la référence Instancie et initialise le Proxy daccès au service # utilisation avec une référence > java –D «service.reference=localhost:12345» step7.Client «Tout le Monde »
80 c Raphaël Marvie Code Client public class Client { private Service ref ; public Client () throws Exception { this.ref = (Service) this.ref2proxy () ; } // other methods unchanged
81 c Raphaël Marvie Code Client public Proxy ref2proxy () throws Exception { Properties props = System.getProperties () ; String ref = props.getProperty ("service.reference") ; if (ref == null) throw new Exception ("no server reference given") ; String parts[] = ref.split (":") ; if (parts.length < 2) throw new Exception ("malformed reference") ; String host = parts [0] ; int port = Integer.parseInt (parts [1]) ; return new Proxy (host, port) ; }
82 c Raphaël Marvie Bénéfices et limitations Bénéfices Le code client nest pas lié à une instance de serveur Possibilité dutiliser différents serveurs Limitations Un seul objet service par serveur Un client ne peut utiliser quun objet à la fois Le client doit connaître le type de la référence à la compilation