Systèmes et Applications Répartis

Programming, Java RMI, Distributed Systems · course

Voir tous les documents en programmation

Systèmes et Applications Répartis

Java RMI

ENSI – 2012/2013

Contenu de la présentation

 Introduction (Client-Serveur)

 Intérêt des objets pour la construction d’applications réparties  client-serveur à objet

 Architecture de Java RMI

 Schéma global, rôle des talons  Architecture, rôle des couches RRL et transport

 Mode opératoire

 Exportation de l’objet  Service de nommage  Codage : interface, serveur, client  Compilation et activation

 Passage des paramètres

 objet local, objet distant

 Appel en retour  Chargement dynamique  Activation d’objets distants  Garbage collector  Conclusion

2

Intérêt des objets pour la construction d’applications réparties

 Encapsulation

 L’interface (méthodes + attributs) est la seule voie d’accès à l’état

interne, non directement accessible

 Classes et instances

 Mécanismes de génération d’exemplaires conformes à un même

modèle  Héritage

 Mécanisme de spécialisation : facilite récupération et réutilisation de

l’existant  Polymorphisme

 Mises en œuvre diverses des fonctions d’une interface  Remplacement d’un objet par un autre si interfaces “compatibles”  Facilite l’évolution et l’adaptation des applications

ENSI

Systèmes et applications répartis

3

Client-serveur « à objet »

 objets "langage"

– représentation propre au

langage : instance d'une classe

– exemple : Java RMI

 objets "système"

– représentation "arbitraire" définie par l'environnement d'exécution

– exemple : CORBA

 Motivations

– propriétés de l’objet (encapsulation,

modularité, réutilisation, polymorphisme, composition)

– objet : unité de désignation et de

distribution

 Eléments d'une "invocation"

– référence d'objet – identification d'une méthode – paramètres d'appel et de retour (y

compris signal d'exception)

• passage par valeur : types élémentaires et

types construits

• passage par référence

4

Appel de méthode à distance Remote Method Invocation (RMI)

 Solution proposée par SUN pour adapter le principe des RPC à la

programmation orientée objet.

 Technologie fondée sur le langage Java (à partir du JDK 1.1)

 Localisation d'objets distants

 Les échanges respectent un protocole propriétaire : Remote Method Protocol.

 Invocation de méthodes sur des objets distants

 Transfert d'objets en paramètres ou en retour (serialization)

ENSI

Systèmes et applications répartis

5

RMI : architecture logique

ENSI

Systèmes et applications répartis

6

La couche des références distantes

 Plusieurs protocoles d’invocation possibles :

 Invocation point à point (Unicast)  Invocation vers des groupes de réplication (Multicast)

 Stratégie de reconnexion (si un objet devient inaccessible)

 Deux composantes coopérantes :

 la composante côté client (client-side)  la composante côté serveur (server-side)

 Transmission de données entre couches transport par une

connexion orientée flux

ENSI

Systèmes et applications répartis

7

La couche transport

 La couche transport de Java-RMI effectue :

 Mise en place, gestion, surveillance de la connexion

 Ecoute des appels arrivants

 Maintien d’une table d’objets distants pour l’espace d’adressage

 Localisation du dispatcher pour la cible d’un appel distant et transmission de la

connexion

 Elle réalise les connexions réseaux basées sur les flux entre les JVM.

 Elle emploie un protocole de communication propriétaire (JRMP : Java

Remote Method Protocol) basé sur TCP/IP.

ENSI

Systèmes et applications répartis

8

Personnaliser la couche Transport des RMI  Par défaut, TCP est utilisé par la couche de transport RMISocketFactory (classes java.net.Socket et

java.net.SocketServer)

 Motivation

 utiliser d’autres classes (que Socket et SocketServer) basées sur

 TCP pour de la compression, du chiffrage, …

– Remarque : RMI over SSL utilise cette technique

 ou non (UDP)

 Etape 1

 Écrire 2 sous classes de

 java.rmi.RMIClientSocketFactory,  java.rmi.RMICServerSocketFactory

 qui utilisent 2 autres classes de transport que

 java.net.Socket  Java.net. ServerSocket

 Etape 2

 Spécifier les factories dans le constructeur de l’objet distant qui hérite de la classe UnicastRemoteObject  protected UnicastRemoteObject(int port, RMIClientSocketFactory csf, RMICServerSocketFactory ssf)

ENSI

Systèmes et applications répartis

9

Appel de méthode à distance Remote Method Invocation (RMI)

objet client

objet serveur

Talon client

Talon serveur

Système de communication

état

Methode_1

.

. Methode_n

Référence d'objet + méthode + arguments

Résultat ou exception

désignation envoi de requêtes exécution de requête retour de résultat

référence

appel

10

Java RMI Mode opératoire côté serveur

rmiregistry

Naming

Serveur

Skeleton

JVM Client

JVM Serveur

Client

11

Java RMI Mode opératoire côté serveur

 1 - L'objet serveur s'enregistre auprès du Naming de sa JVM

(méthode rebind)

 2 - L ’objet skeleton est créé, celui-ci crée le port de

communication et maintient une référence vers l'objet serveur

 3 - Le Naming enregistre l'objet serveur, et le port de communication utilisé auprès du serveur de noms

 L'objet serveur est prêt à répondre à des requêtes

12

Java RMI Mode opératoire côté client

rmiregistry

Naming

 Client

Stub

JVM Client

13

Naming

Serveur

Skeleton

JVM Serveur

Java RMI Mode opératoire côté client

4 - L'objet client fait appel au Naming pour localiser

l'objet serveur (méthode lookup)

5 - Le Naming récupère les "références" vers l'objet

serveur, ...

6 - crée l’objet Stub et ... 7 - rend sa référence au client 8 - Le client effectue l'appel au serveur par appel à

l’objet Stub

14

 La souche client :

La souche client (stub)

Initialise l’appel vers un objet distant (via la couche des références

distantes )

Sérialise les arguments sous forme d’un unique flot de sortie

Informe la couche des références distantes que l’appel peut être

invoqué

Désérialise le flot d’entrée contenant la valeur de retour ou une

exception

Informe la couche des références distantes que l’appel est achevé

ENSI

Systèmes et applications répartis

15

La souche serveur (skeleton)

 La souche serveur :

Reçoit l’appel par une méthode unique (aiguilleur)

Désérialise le flot d’entrée des arguments

Prépare l’appel vers l’implémentation réelle de l’objet distant

Distribue l’appel vers la bonne méthode cible

Sérialise les valeurs de retour ou les exceptions dans le flot de

sortie

ENSI

Systèmes et applications répartis

16

Exportation de l'objet

Pour exporter un objet :  Utilisation de la classe UnicastRemoteObject

 L'objet reste alors actif et accessible en permanence  Si la JVM dans laquelle il s'exécute est arrêtée, l'objet disparaît et sa référence

également

 Variante possible : Activatable

Publicité

 Permet de n'activer l'objet que quand il est sollicité  Via un mécanisme et une JVM particuliers  Permet de limiter le nombre d'objets actifs en même temps : gain de mémoire

au besoin

 Plus complexe à utiliser

ENSI

Systèmes et applications répartis

17

La classe UnicastRemoteObject

 Serveurs démarrés explicitement  Utilise des comm TCP  Pour des comm. P2P entre processus actifs  Unicast : l'objet de la classe implémentant l'interface n'existe qu‘en

un seul exemplaire sur une seule machine

 L'objet meurt avec la fin de l'exécution du serveur qui le lance

ENSI

Systèmes et applications répartis

18

La classe UnicastRemoteObject

 La classe abstraite RemoteObject redéfinit plusieurs méthodes de

Object et en ajoute pour les objets distants  hashCode, equals, toString  getRef, toStub, writeObject, readObject

 La classe abstraite RemoteServer définit des méthodes

communes à tous les serveurs  unexportObject, getClientHost, …

 La classe UnicastRemoteObject implémente les objets distants

non répliqués (mono-serveur)  exportObject, …

ENSI

Systèmes et applications répartis

19

La classe UnicastRemoteObject

La principale fonction de cette classe se manifeste lors de la création d’une instance de l’objet distant étendant cette classe. Le constructeur crée une instance de stub pour l’objet et retourne ce stub comme résultat de la création

Le contenu d’un stub

Un stub contient essentiellement une variable ref de type RemoteRef qui contient la localisation de l’objet (adresse IP, port)

Un appel de méthode se fait par appel de ref.invoke(…) qui

utilise les sockets pour la communication

ENSI

Systèmes et applications répartis

20

Le service de nommage: Enregistrement d'un service

ENSI

Systèmes et applications répartis

21

Le service de nommage: Accès à une référence distante

ENSI

Systèmes et applications répartis

22

Le service de nommage

 Une URL est formée pour l'enregistrement puis l'accès sous la forme :

 rmi://<host_name>[:port]/[service_name]

 Le port de liaison par défaut est le port TCP 1099  La classe Naming encaspule le dialogue avec plusieurs objets serveurs

de liaison  Peut utiliser un ou plusieurs registry par application distribuée  On doit enregistrer un objet sur un registry local  5 opérations statiques pour enregistrer des objets et récupérer leurs références

ENSI

Systèmes et applications répartis

23

Le service de nommage

 L’ objet serveur de liaison

 réalise la correspondance nom avec stub  Interface d’un objet serveur de liaison

 Implémentation par défaut de l’objet serveur de liaison

 La classe LocateRegistry

 localise ou active un objet serveur de liaison  En général invisible au client (appelé en interne par Naming)  Méthodes Statiques

 Registry createRegistry(int port)

– crée un objet serveur de liaison sur le port spécifié

 Registry getRegistry(int port)

– récupère l’objet serveur de liaison qui a été crée  Registry getRegistry(server name, port number)

– essaie de trouver un démon rmiregistry sur la machine server name et sur le port port

ENSI

number

Systèmes et applications répartis

24

Le service de nommage

ENSI

Systèmes et applications répartis

25

La notion d’interface

 L’interface constitue le contrat - abstrait liant objets serveurs et

objets clients Elle est destinée à être implémentée par l’OD et constitue la base

d’appel pour les objets clients

Elle définie les signatures (noms, types de retour, paramètres) d’un

ensemble de méthodes et seules ces méthodes seront accessibles par un objet client

 Pour RMI, c’est une interface Java traditionnelle … mais dérivant de la

classe java.rmi.Remote

ENSI

Systèmes et applications répartis

26

Java RMI Manuel d'utilisation

 Codage

 Description de l’interface du service  Ici pas d’IDL séparé : Java sert d’IDL

 Ecriture du code du serveur qui implante l’interface  Ecriture du client qui appelle le serveur

 Compilation

 Compilation des sources (javac)  Création des Stub et Skel par rmic (faite automatiquement à partir de JDK 5.0)

 Activation

 Lancement du serveur de noms (rmiregistry)

 L'accès à une référence distante chez le client (par java.rmi.registry.Registry)

 Lancement du serveur  Lancement du client

27

Java RMI Manuel d'utilisation

 Définition de l'interface de l'objet réparti  interface : "extends java.rmi.Remote"  methodes : "throws java.rmi.RemoteException "  paramètres sérialisables : "implements Serializable "

 Ecrire une implémentation de l'objet serveur

 classe : étend une des sous-classes de java.rmi.server.RemoteServer comme

java.rmi.server.UnicastRemoteObject

 Pas de spécialisation et le constructeur doit exécuter l'instruction suivante :

UnicastRemoteObject.exportObject(this);

 5 Packages

 java.rmi : pour accéder à des objets distants  java.rmi.server : pour créer des objets distants  java.rmi.registry : lié à la localisation et au nommage d’objets distants  java.rmi.dgc : ramasse-miettes pour les objets distants  java.rmi.activation support pour l ’activation d ’objets distants.

28

Java RMI : écriture de l’interface

 Mêmes principes de base que pour l’interface d’un objet local

 Principales différences

 L’interface distante doit être publique

 L’interface distante doit étendre l’interface java.rmi.Remote

 Chaque méthode doit déclarer au moins l’exception java.rmi.RemoteException

 Tout objet distant passé en paramètre doit être déclaré comme une interface

(passage de la référence de l’objet)

 Tout objet local passé en paramètre doit être sérialisable

29

Java RMI Exemple : Interface

fichier Hello.java

public interface Hello extends java.rmi.Remote { String sayHello() throws java.rmi.RemoteException; }

Description de l ’interface

30

Java RMI : écriture du serveur

 Serveur = la classe qui implémente l’interface

Spécifier les interfaces distantes qui doivent être implémentées objets locaux passés par copie (il doivent implémenter l’interface

java.io.serializable)

objets distants passés par référence (actuellement référence à un stub)

C’est un objet java standard

définir le constructeur de l’objet fournir la mise en œuvre des méthodes pouvant être appelées à distance ainsi que celle des méthodes n’apparaissant dans aucune interface

implémentée

Créer au moins une instance du serveur Enregistrer au moins une instance dans le serveur de nom (rmiregistry)

31

Java RMI : écriture du serveur

 L’objet distant servant peut être d’une sous classe de la classe

implémentant l’interface

 Le serveur peut créer et enregistrer plusieurs objets appartenant à

une ou plusieurs classes

 L’enregistrement peut se faire auprès de plusieurs rmiregistry

 Il faut prévoir une procédure d’arrêt (shutdown) du serveur

 Arrêt des objets UnicastRemoteObject public static void Naming.unbind(Stringname) public static boolean UnicastRemoteObject.unexportObject(Remote,

boolean force)

ENSI

Systèmes et applications répartis

32

Java RMI Exemple : Implémentation de l’objet distant

import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject;

fichier HelloObj.java

public class HelloObj extends UnicastRemoteObject implements Hello { private String msg;

// Constructeur public HelloObj(String msg) throws RemoteException {

this.msg = msg;

}

// Implémentation de la méthode distante. public String sayHello() throws RemoteException {

return "Hello world: " + msg;

Réalisation Du serveur

}

}

33

Java RMI Exemple : Implémentation de l’objet distant

fichier HelloObj.java

import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject;

public class HelloObj implements Hello { private String msg;

// Constructeur public HelloObj(String msg) throws RemoteException {

this.msg = msg; UnicastRemoteObject.exportObject(this);

}

// Implémentation de la méthode distante. public String sayHello() throws RemoteException {

return "Hello world: " + msg;

}

} 34

Réalisation Du serveur (autre approche)

Java RMI Exemple : Serveur

fichier HelloServeur.java

import java.rmi.*;

public class HelloServeur {

public static void main(String args[]) {

try {

// Crée une instance de l ’objet serveur. HelloObj obj = new HelloObj("HelloServeur"); // Enregistre l'objet créer auprès du serveur de noms. Naming.rebind(Hello.class.getName(), obj); System.out.println("HelloServer" + " bound in registry");

Réalisation du Serveur d’objets

} catch (Exception exc) {… }

}

}

ATTENTION : dans cet exemple le serveur de nom doit être activé avant la création du serveur

35

Java RMI Activation du serveur de nom par le serveur

fichier HelloServeur.java

public static void main(String args[]) { int port; String URL;

try { // transformation d ’une chaîne de caractères en entier Integer I = new Integer(args[0]); port = I.intValue(); } catch (Exception ex) { System.out.println(" Please enter: Server <port>"); return; }

try { // Création du serveur de nom - rmiregistry Registry registry = LocateRegistry.createRegistry(port);

Réalisation du serveur (autre approche)

// Création d ’une instance de l ’objet serveur HelloObj obj = new HelloObj("Coucou, je suis le serveur de port : "+port);

// Calcul de l ’ ’URL du serveur URL = "//"+InetAddress.getLocalHost().getHostName()+":"+port+

Hello.class.getName();

registry.rebind(URL, obj); } catch (Exception exc) { ...}}

36

Java RMI Exemple : Client

import java.rmi.Naming;

fichier HelloClient.java

public class HelloClient { public static void main(String args[]) { try { // Récupération d'un stub sur l'objet serveur. Hello obj = (Hello) Naming.lookup("//suldrun/"+

Hello.class.getName());

// Appel d'une méthode sur l'objet distant. String msg = obj.sayHello(); // Impression du message. System.out.println(msg); } catch (Exception exc) { … } }}

Réalisation du client

 On récupère en fait une référence sur une instance de HelloObj_Stub

 Le talon local côté client qui sert de proxy pour l'accès à l'instance de HelloObj côté serveur

37

Java RMI Exemple : Client (Recherche du rmiregistry)

fichier HelloClient.java

import java.rmi.Naming;

public class HelloClient { public static void main(String args[]) { try { // Récupération d'un stub sur l'objet serveur.

Publicité

if (args.length > 0) obj = (Hello) LocateRegistry

.getRegistry(args[0]).lookup(Hello.class.getName());

else obj = (Hello)LocateRegistry.getRegistry()

.lookup(Hello.class.getName());

// Appel d'une méthode sur l'objet distant. String msg = obj.sayHello(); // Impression du message. System.out.println(msg); } catch (Exception exc) { … } } }

38

Réalisation du client

Java RMI Compilation

Compilation de l’interface, du serveur et du client

javac Hello.java HelloObj.java HelloServeur.java

HelloClient.java

Génération des talons

Générés automatiquement à partir du JDK 5.0 rmic HelloObj (JDK 1.4 ou antérieur) skeleton dans HelloObj_Skel.class stub dans HelloObj_Stub.class. Les fichiers .java générés sont effacés sauf si l'option -

keepgenerated est spécifiée.

39

Java RMI Déploiement

 1) Activation du serveur de nom

 start rmiregistry (Windows) ou rmiregistry & (Unix)

 2) Activation du serveur  java HelloServeur  L'exécution d'un serveur RMI nécessite de fixer quelques propriétés:

 L'hôte et le chemin d'accès des classes (de l'interface, éventuellement des implémentations) du

serveur

– -Djava.rmi.server.codebase=<repertoire> – Exemple :

» java -Djava.rmi.server.codebase=http://hostname/… HelloServeur » -Djava.rmi.server.codebase=file://dev/hello/myclasses/ » -Djava.rmi.server.codebase=file:/c:\dev\hello\myclasses/ » path indiquant à quel endroit la machine virtuelle cliente va pouvoir chercher le code du stub

Unix Win32

– -Djava.rmi.server.hostname=<hote>

» Nécessaire si le client et le serveur ne sont pas sur la même station

 Le fichier définissant la politique de sécurité – -Djava.security.policy=<fichier_policy>

 3) Activation du client  java HelloClient

40

Passage d'arguments

 Il y a 3 possibilités de passage d'arguments lors de l'invocation d'une méthode

distante  Le paramètre est d'un type primitif : passage par valeur  Le paramètre est un objet

 Il est sérialisé et envoyé au serveur

– il doit donc implémenter java.io.Serializable ou java.io.Externalizable

 Une référence distante est envoyée :c’est l’objet Stub qui est sérialisé et envoyé à l’objet distant : quand l’objet distant invoque un méthode sur le paramètre, l’invocation est distante.

– Pour cela 3 conditions doivent être respectées :

» L'objet en question hérite de la classe UnicastRemoteObject; » Il implémente une interface partagée avec l'autre partie (client ou serveur); » Sa référence distante (Stub) est accessible par l'autre partie.

 Idem pour la valeur de retour d'une méthode distante

ENSI

Systèmes et applications répartis

41

Sérialisation d'objets

 La sérialisation est une opération (on parle aussi de marshalling et

d'unmarshalling) qui consiste à transformer un objet dans un format transférable par un flux de données (cf. les classes ObjectInputStream et ObjectOutputStream du package java.io). On s'en sert principalement dans 2 cas :  Sauvegarder un objet dans un fichier  Déplacer un objet d'une machine virtuelle vers une autre

 C'est donc une copie de l'objet qui est envoyée au serveur (ou au client

dans le cas d'une valeur de retour).

 Pour être sérialisable, un objet doit implémenter l'interface

java.io.Serializable;

 Tous les objets contenus dans l'objet seront aussi sérialisés (ils doivent

donc être aussi sérialisables);

 La sérialisation est effectuée automatiquement.

ENSI

Systèmes et applications répartis

42

Java RMI Passage en paramètre d’un objet local

Java VM

Java VM

O2

Objet objet1 m ( O2 )

clone_O2

Skeleton R_objet1

Client R_objet1.m ( O2 )

Stub R_objet1

43

Java RMI Passage en paramètre d’un objet local dont la classe est inconnue du serveur

ENSI

Systèmes et applications répartis

44

Java RMI Passage en paramètre d’un objet local dont la classe est inconnue du serveur

ENSI

Systèmes et applications répartis

45

Java RMI Passage en paramètre d’un objet local : exemple

ENSI

Systèmes et applications répartis

46

Java RMI Passage en paramètre d’un objet distant

Objet O2

Java VM

Java VM

Client R_objet1.m ( R O2 )

Stub R_O2

Objet objet1 m ( R_objet )

Stub R_objet1

47

Skeleton R_objet1

Java RMI Passage en paramètre d’un objet distant

Objet O2

Java VM

Java VM

Client R_objet1.m ( R O2 )

Stub R_O2

Objet objet1 m ( R objet )

Stub R_O2

Stub R_objet1

Skeleton R_objet1

48

Java RMI Passage en paramètre d’un objet distant

Si jamais le type n’est pas disponible

localement, il est chargé dynamiquement (RMIClassLoader)

Pour les paramètres qui seraient déjà des références d’OD,

l’objet amorce (Stub) est passé : impossible de passer en paramètre un objet uniquement visible par les classes serveurs

ENSI

Systèmes et applications répartis

49

Java RMI Passage en paramètre d’un objet distant

 Méthode 1

 Le Stub est celui d’un objet distant déjà servi

 Méthode 2 : Objet Distant Temporaire

But:

L’objet distant est local au client et n’est utilisé que pour la durée d’une ou plusieurs invocations distantes depuis

le client

Solution

Exporter l’objet avec la méthode

UnicastRemoteObject.exportObject()

L’objet doit implémenter l’interface Unreferenced

pour être ramassé par le GC

ENSI

Systèmes et applications répartis

50

Objet Distant Temporaire : Le client

ENSI

Systèmes et applications répartis

51

Objet Distant Temporaire Le serveur temporaire

ENSI

Systèmes et applications répartis

52

Objet Distant Temporaire L’objet distant et son serveur

ENSI

Systèmes et applications répartis

53

Objet Distant Temporaire Déroulement de l’exécution

ENSI

Systèmes et applications répartis

54

Appels en retour

 La partie serveur peut avoir besoin d'appeler

une méthode sur la partie client  Callback : appel en retour

 Deux moyens pour le serveur de connaître le

client  Rechercher sa référence via son nom dans

le registre

 Récupérer sa référence via l'appel de la

méthode

 Exemple : implémentation du patron Observer

 Un élément (l'observé) gère une donnée/un

état susceptible de changer

 D'autres éléments (les observateurs)

informent l'observé qu'ils veulent être tenus au courant des changements de valeur de la donnée

ENSI

Systèmes et applications répartis

55

Appels en retour : Exemple

Interface d'opérations, côté observateur

Une opération qui sera appelée par l'observé

quand la donnée observée (un entier ici) changera de valeur

ENSI

Systèmes et applications répartis

56

Appels en retour : Exemple

 Interface d'opérations côté observé

 Une méthode pour s'enregistrer comme observateur de la valeur et une

pour se désenregistrer

 Le paramètre est de type IChangeValue

C'est-à-dire un objet implémentant l'interface permettant de

signaler un changement de valeur

ENSI

Systèmes et applications répartis

57

Appels en retour : Exemple

 Implémentation de l'observateur

ENSI

Systèmes et applications répartis

58

Appels en retour : Exemple

Implémentation de l'observé

ENSI

Systèmes et applications répartis

59

Appels en retour : Exemple

Implémentation de l'observé (suite)

ENSI

Systèmes et applications répartis

60

Appels en retour : Exemple

Lancement de l'observé

Lancement d'un observateur

ENSI

Systèmes et applications répartis

61

Appels en retour

 Note 1

 Quand un observateur appelle subscribe sur l'observé distant, il passe sa

référence « distante » car il implémente une interface Remote

 L'appel de newValue se fait donc bien sur l'observateur distant (distant du

point de vue de l'observé qui appelle newValue)

 Note 2

 On peut noter que les observateurs ne se sont pas enregistrés via le registry  On peut en effet communiquer avec un objet distant à partir du moment où

il s'est exporté

Publicité

 L'enregistrement via le registry n'est utile que pour récupérer sa référence à

partir de son nom associé

 Inutile ici car les observateurs passent eux-mêmes leurs références à

l'observé

ENSI

Systèmes et applications répartis

62

Appels concurrents d'opérations

 Les méthodes de l'observé sont marquées avec synchronized

Pour éviter des incohérences en cas d'appels concurrents

 Côté servant

En interne de RMI, une opération invoquée dynamiquement ou par le

skeleton l'est dans un thread créé à cet usage

Accès concurrent possible si plusieurs clients distants demandent en

même temps à exécuter une opération

Toujours avoir cela en tête quand on implémente un servant même si on

ne voit pas explicitement l'aspect concurrent

ENSI

Systèmes et applications répartis

63

Chargement dynamique des stubs

 Rappel : un objet client ne peut utiliser un objet distant qu’au

travers des stubs

 RMI permet l’utilisation des OD dont les stubs ne sont pas

disponibles au moment de la compilation

 A l’exécution, RMI réclamera au serveur le stub client manquant et

le téléchargera dynamiquement (byte code) Le serveur est lancé en précisant un codebase Le client est lancé sans codebase et retrouvera les classes via les

informations envoyées par le registry

ENSI

Systèmes et applications répartis

64

Chargement dynamique des classes

 Plus généralement, le système RMI permet le chargement

dynamique de classes comme les stubs, les interfaces distantes et les classes des arguments et valeurs de retour des appels distants

 C’est un chargeur de classes spécial RMI qui s’en charge :

java.rmi.server.RMIClassLoader

ENSI

Systèmes et applications répartis

65

Charger des classes de manière dynamique

 Les définitions de classe sont hébergées sur un serveur Web.  Les paramètres, les stubs sont envoyés au client via une connexion

au serveur Web.

 Pour fonctionner, une application doit télécharger les fichiers de

classe.

Chargement dynamique  Cela évite de disposer localement de toutes les définitions de

classe.

 Les mêmes fichiers de classe (même version) sont partagés par tous

les clients.

 On ne charge que les classes dont on a besoin.

ENSI

Systèmes et applications répartis

66

Fichiers nécessaires si pas de chargement dynamique

Côté Client

Côté Serveur

– l’interface : Hello – le stub : HelloObj_Stub – le client : HelloClient

– l’interface : Hello – l’objet : HelloObj – le serveur d’objets :

HelloServeur – Le skeleton :

HelloObj_Skel

ENSI

Systèmes et applications répartis

67

Fichiers nécessaires si chargement dynamique

Côté client

Côté serveur

– Le client : HelloClient

– Le serveur HelloServeur

Récupérer les fichiers de classe à partir du serveur web

Serveur Web : Interface : Hello

Stub : HelloObj_stub Objet : HelloObj

ENSI

Systèmes et applications répartis

68

Le client peut être lui même dynamique

Côté Client  Le client : DynamicClient  Chargement dynamique du client et

Côté Serveur  Le serveur d’objets :

HelloServeur

de l’interface à partir d’un répertoire local. Si non disponibles localement, ils sont recherchés sur le serveur Web spécifié.

 L’exécution de HelloClient permet d’obtenir la référence de l’objet HelloObj et l’appel distant de sa méthode

 Chargement dynamique de l’objet HelloObj à partir du serveur Web

 Enregistrement de l’objet dans

RMIregistry (bind)

 Attente de requêtes des clients

Serveur Web : Interface : Hello

Stub : HelloObj_stub Objet : HelloObj Client : HelloClient

ENSI

Systèmes et applications répartis

69

Principe du chargement dynamique

 A l’enregistrement (dans rmiregistry) de l ’objet distant, le codebase est

spécifié par java.rmi.server.codebase.  URL est de type « file », « ftp » ou « http »  Exemples

 $ java -Djava.rmi.server.codebase=file:///home/TPRMI/test-rmi/ Serveur  $ java -Djava.rmi.server.codebase=http://www.SAR.ensi.rnu.tn/TPRMI/test-rmi/ Serveur

 A l’appel de bind(), le registre utilise ce codebase pour trouver les fichiers

de classe associés à l’objet.

 Le client recherche la définition de classe du stub dans son classpath. S’il ne

la trouve pas, il essayera de la récupérer à partir du codebase.  La méthode LoadClass de RMIClassLoader charge la classe à partir du codebase

spécifié.

 Une fois que toutes les définitions de classe sont disponibles, la méthode

proxy du stub appelle les objets sur le serveur.

ENSI

Systèmes et applications répartis

70

Principe du chargement dynamique

ENSI

Systèmes et applications répartis

71

Principe du chargement dynamique : L ’enregistrement de l ’objet

ENSI

Systèmes et applications répartis

72

Principe du chargement dynamique : La récupération du Stub

ENSI

Systèmes et applications répartis

73

Principe du chargement dynamique : Invocation d ’une méthode

ENSI

Systèmes et applications répartis

74

Les différentes étapes d’un chargement dynamique

 Écrire les classes correspondant respectivement à l’interface et à l’objet.  Les compiler.  Générer le Stub correspondant à l’objet.  Installer tous les fichiers de classe sur un serveur Web.  Écrire le serveur dynamique.  Installer rmiregistry au niveau de la machine du serveur.  Lancer le serveur en lui précisant l’URL des fichiers de classe afin qu’il puisse

charger dynamiquement le fichier de classe correspondant à l’objet, l’instancier (le créer) et l’enregistrer auprès de rmiregistry.

 Sur la machine du client, écrire le code du client.  Compiler le client statique et l’installer éventuellement sur le site Web.  Compiler le client dynamique et le lancer en précisant l’URL des fichiers de classe.

ENSI

Systèmes et applications répartis

75

Chargement dynamique et sécurité

 Si le code du stub n’est pas présent sur le site local, le protocole RMI prévoit le chargement dynamique du stub en utilisant un serveur web et le protocole HTTP  java -Djava.rmi.server.codebase=http://<hostname>/… HelloServeur

 Si chargement dynamique…

 le chargeur dynamique utilisé par RMI (RMIClassLoader) regarde si la classe

demandée correspond au niveau de sécurité requis

 utilisation d’un SecurityManager  C’est la classe java.rmi.RMISecurityManager

 créer et installer le « gestionnaire de sécurité » (dans le client)  System.setSecurityManager(new RMISecurityManager());

76

Sécurité et RMI

 L'ensemble des permissions accordées par ce SecurityManager sont définies soit :

 en surchargeant certaines méthodes de l'instance (cf. la classe

java.lang.SecurityManager)

 en écrivant un fichier externe indiqué dans l'option d'exécution

 -Djava.security.policy=<fichier_policy>  Example :

java -Djava.security.policy=client.policy HelloClient

 Syntaxe simplifiée d'un fichier policy :

grant { permission <permission_class_name> [target_name] [,action] permission <permission_class_name> [target_name] [,action] ... };

ENSI

Systèmes et applications répartis

77

Exemples de fichiers policy

grant { permission java.security.AllPermission; }; grant { permission java.io.FilePermission "/tmp/*",

"read,write";

permission java.util.PropertyPermission

"user.country", "read";

permission java.net.SocketPermission

"localhost:1099", "connect,accept,resolve";

};

ENSI

Systèmes et applications répartis

78

Exemple : serveur dynamique

fichier DynamicServer.java

import java.rmi.Naming; import java.rmi.Remote; import java.rmi.RMISecurityManager; import java.rmi.server.RMIClassLoader; import java.util.Properties; import java.lang.reflect.Constructor; public class DynamicServer { public static void main(String[] args) { System.setSecurityManager(new RMISecurityManager()); try {

Properties p= System.getProperties(); String url=p.getProperty("java.rmi.server.codebase"); Class ClasseServeur = RMIClassLoader.loadClass(url, "HelloObj"); Constructor[] C = ClasseServeur.getConstructors(); Naming.rebind("rmi://sinus.rnu.ensi.tn:1099/MyHello", (Remote)C[0].newInstance(new Object[]{args} )); System.out.println("Objet Hello lié dans le RMIregistry"); System.out.println("Attente des invocations des clients …"); }

catch (Exception e) {

System.out.println("Erreur de liaison de l'objet HelloObj"); System.out.println(e.toString());

} } // fin du main } // fin de la classe

79

Exemple : Le client

fichier HelloClient.java

import java.rmi.*; public class HelloClient { public HelloClient () { try{ Hello obj = (Hello) Naming.lookup ("rmi://sinus.rnu.ensi.tn:1099/MyHello"); // Appel d'une méthode sur l'objet distant. String msg = obj.sayHello(); // Impression du message. System.out.println(msg); } catch (Exception e) { System.out.println ("Erreur d'accès à l'objet distant "); System.out.println (e.toString()); } } }

80

Exemple : Le client dynamique

fichier DynamicClient.java

import java.rmi.RMISecurityManager; import java.rmi.server.RMIClassLoader; import java.util.Properties; import java.lang.reflect.Constructor; public class DynamicClient { public DynamicClient (String [] args) throws Exception { Properties p = System.getProperties(); String url = p.getProperty("java.rmi.server.codebase"); Class ClasseClient = RMIClassLoader.loadClass(url, "HelloClient"); // lancer le client Constructor [] C = ClasseClient.getConstructors(); C[0].newInstance( new Object[]{args} ); } // vérifier le passage de paramètres public static void main (String [] args) { System.setSecurityManager(new RMISecurityManager()); try{

DynamicClient cli = new DynamicClient(args) ;

} catch (Exception e) {

System.out.println (e.toString());

}}}

81

Exemple : Compilation et exécution

 sinus> ls HelloObj.java Hello.java DynamicServer.java  sinus> javac *.java  sinus> rmic -v1.2 HelloObj  sinus> mv Hello*.class /var/www/html/TP/rmi

Le répertoire destination des fichiers de classe doit être accessible par http.

 sinus> ls *.class DynamicServer.class  sinus>rmiregistry &  sinus>java -Djava.security.policy=client1.policy -Djava.rmi.server.codebase=

http://sinus.ensi.rnu.tn/TP/rmi DynamicServer HelloServeur

Objet lié Attente des invocations des clients …

----------------------------------

ENSI

Systèmes et applications répartis

82

Exemple : Compilation et exécution

 cosinus>ls *.java HelloClient.java DynamicClient.java  cosinus>javac *.java  cosinus>java -Djava.security.policy=client1.policy -Djava.rmi.server.codebase=

http://sinus.ensi.rnu.tn/TP/rmi DynamicClient

Hello world : HelloServeur  Le chargement de HelloClient se fera à partir du répertoire local alors que Hello et HelloObj_Stub seront chargés à partir du serveur Web spécifié dans la commande.

 Note

 Si à l'exécution des exceptions UnmarshallException, AccessDeniedException ou

ClassNotFoundException sont levées

 Correspond souvent à des tentatives de téléchargement de classes mais sans avoir les

permissions suffisantes ou sans savoir où aller les récupérer

 Si c'est du côté serveur : le registry n'arrive pas à récupérer le stub, le codebase a été