Accès à distance avec Middleware Java RMI
Accès à distance avec Middleware Java RMI
ème
Licence Informatique 3 année
Eric Cariou
[Link]@[Link]
1
TP 4 : accès données à distance
But du TP 4
Accéder à distance à une (mini) base de données gérant
des informations sur des personnes
Architecture de l'application
Un « data manager » unique dans le système gère toutes
les données
Un serveur sert d'accès à ce data manager
Les parties client se connectent au serveur pour accéder
aux données
Les utilisateurs des parties client appellent localement
(sur leur partie client) les mêmes services que ceux
offerts par le data manager
2
TP 4 : accès données à distance
Rappel de l'architecture
appels « logique »
Classe accédant de services Classes com-
Data Manager
à DataManager muniquantes
appels réels
de services
Serveur/ Classes
Client ThreadClient permettant la
Communication via TCP
communication
Machine A Machine B
5
TP 4 : accès données à distance
Étude évolutivité du système (suite)
Ajout d'un service au niveau du data manager implique
une modification non négligeable de toutes les classes
Evolutivité relativement lourde à mettre en oeuvre
Idée pour faciliter l'évolutivité
Ne plus avoir des types de messages spécifiques à une
requête
Avoir un message générique contenant les paramètres de la
requête
Signature de l'opération et paramètres à utiliser
Avoir un message générique contenant une valeur de retour
Ajout d'un service au niveau du data manager ne
nécessite plus de création de nouveaux messages
associés 6
TP 4 : accès données à distance
Messages génériques
Relativement simple à réaliser
Mais ne simplifie pas le code coté client et serveur
Doit toujours « décoder » la requête
Le serveur doit déterminer l'opération à appeler sur le data manager en
analysant le contenu du message générique de requête
Idée pour éviter ces décodages coté serveur
Appeler automatiquement l'opération à partir des informations
contenues dans le message générique de requête
Avec une section de code unique et générique, il faut pouvoir
appeler la « bonne » opération avec les bons paramètres
A partir des infos contenues dans le message de requêtes
Solution : invocation dynamique de l'opération via introspection
et réflexion
7
Introspection
Introspection : capacité à s'interroger sur soi-même
En Java : accéder aux caractéristiques d'un objet
Liste des attributs, méthodes, constructeurs, interfaces ...
En dynamique, pendant l'exécution du programme
Classe [Link]
Méta-classe : classe décrivant une classe
Une instance de Class décrit le contenu d'une classe Java du
programme
Contient des méthodes pour
Lister ou rechercher les attributs, les méthodes
Instantier un objet de la classe représentée par l'instance de la
classe Class
8
Introspection
Classe [Link]
Description d'une méthode
Nom de la méthode, types des attributs, type du paramètre de
retour ...
Méthode invoke permet d'invoquer dynamiquement la méthode
représentée par une instance de Method sur un objet
Autres classes de l'API de réflexion de Java
Classe [Link]
Description d'un attribut d'une classe
Classe [Link]
Description d'un constructeur d'une classe
...
Voir API Java et tutoriaux pour plus d'informations
9
Invocation dynamique de méthode
Exemple : appel de addPersonne sur data manager
// instantiation d'un data manager quelque part dans le programme
DataManager dm = new DataManager();
...
// nom de la méthode à appeler
String methodName = "addPersonne";
12
Réseau physique
Middleware
Plusieurs grandes familles de middleware
Appel de procédure/méthode à distance
Extension « naturelle » de l'appel local d'opération dans le contexte
des systèmes distribués
Une partie serveur offre une opération appelée par une partie client
Permet d'appeler une procédure/méthode sur un élément/objet distant
(presque) aussi facilement que localement
Exemples (dans ordre historique d'apparition)
RPC (Remote Procedure Call) : solution de Sun pour C/Unix
CORBA (Common Object Request Broker Architecture) : standard de
l'OMG permettant l'interopérabilité quelque soit le langage ou le système
Java RMI (Remote Method Invocation) : solution native de Java
Envoi ou diffusion de messages ou événements
Famille des MOM (Message Oriented Middleware)
Event Service de CORBA, JMS de Java
Mémoire partagée
Accès à une mémoire commune distribuée
JavaSpace de Java 13
Middleware
Familles de middlewares, caractéristiques générales
Modèle RPC/RMI
Interaction forte entre parties client et serveur
Appel synchrone (pour le client) d'opération sur le serveur
Généralement, le client doit explicitement connaître le serveur
Peu dynamique (point de vue serveur) car les éléments serveurs doivent
être connus par les clients et lancés avant eux
Mode 1 vers 1 : opération appelée sur un seul serveur à la fois
Modèles à message ou mémoire partagée
Asynchrone et pas d'interaction forte entre éléments
Envoi de message est asynchrone
Pas de nécessité de connaître les éléments accédant à la mémoire
Permet une plus forte dynamicité : ajout et disparation d'éléments
connectés au middleware facilités par les faibles interactions et l'anonymat
Mode 1 vers n
Diffusion de messages à plusieurs éléments en même temps
Accès aux informations de la mémoire par plusieurs éléments
14
Middleware
Caractéristiques que peut assurer un middleware
Transparence à la localisation
Accès à des objets/ressources distantes aussi facilement que
localement et indépendamment de leur localisation
Cas pour tous les middleware
Support de l'hétérogénité des systèmes et des langages
CORBA par exemple : fait interopérer via du RPC/RMI des
éléments logiciels écrits dans n'importe quel langage
Tout autre type de transparence (voir cours intro), selon le
middleware
Services offerts par un middleware
Un ou plusieurs services de communication/interaction
RPC, diffusion de message, mémoire partagée ...
Service de nommage
15
Middleware
Service de nommage du middleware
Pour enregistrer, identifier et rechercher les éléments et
services connectés via le middleware
Service de nommage, cas des middlewares RPC/RMI
Service d'un élément = (interfaces d') opération(s) offerte(s)
par un élément et pouvant être appelée(s) par d'autres
Un élément enregistre les opérations qu'il offre
Recherche d'une opération ou d'un élément, 2 modes
On demande à recevoir une référence sur un élément qui offre
une opération compatible avec celle que l'on cherche
On sait identifier l'élément distant et on demande à récupérer la
référence sur cet élément
Une fois la référence sur l'élément distant connu, on peut
appeler l'opération sur cet élément via cette référence
16
Middleware RPC/RMI
Architecture générale, plusieurs couches
Accès au
middleware Talon Squelette
Interne au
middleware Elt Communication Elt Communication
Système d'
exploitation Couche Réseau Couche Réseau
Communication
via le réseau
Machine A Machine B
17
Middleware RPC/RMI
Éléments de l'architecture générale
2 catégories (comme pour TP4)
Éléments communiquants réalisés par le développeur
Éléments permettant la communication
Description des différents éléments
Éléments dont le code est généré automatiquement via
des outils du middleware
Talon (stub) : élément/proxy du coté client qui offre localement les
mêmes opérations (la même interface) que le servant
Correspond à ce que fait la classe Client du TP4
Squelette (skeleton) : élément du coté serveur qui reçoit les
requêtes d'appels d'opérations des clients et les lance sur le
servant
Correspond à la classe ThreadClient (version sans invocation
18
dynamique)
Middleware RPC/RMI
Description des différents éléments (suite)
Partie client : partie qui appelle l'opération distante
Partie serveur : partie qui offre l'opération distante via une
interface
Appelée aussi « servant » pour certains middleware
A implémenter par le développeur : contient le code des
opérations de l'interface
Correspond à la classe DataManager du TP4
Des 2 cotés : éléments de communication entre parties
client/serveur
Internes au middleware
Attaquent les couches TCP ou UDP via des sockets pour gérer la
communication entre les talons et squelettes
Correspondent à une partie des classes Client, Serveur et
ThreadClient du TP4 19
Middleware RPC/RMI
Fonctionnement général d'un appel d'opération à distance
1. La partie client récupère via le service de nommage une référence
d'objet sur le servant distant
En réalité, une référence sur le talon local
2. La partie client appelle une opération sur cette référence d'objet
Appel synchrone : la partie client attend que l'appel de l'opération soit
terminé pour continuer son exécution
3. Le talon, qui reçoit cet appel, « compacte » (marshall) toutes les
données relatives à l'appel (identificateur opération + paramètres)
4. L'élément de communication envoie les données à l'élément de
communication coté serveur
5. L'élément de communication coté serveur envoie les données au
squelette
6. Le squelette décompacte les données (unmarshall) pour déterminer
l'opération à appeler sur le servant
7. L'opération est appelée sur le servant par le squelette 20
Middleware RPC/RMI
Fonctionnement général d'un appel d'opération à
distance (fin)
8. Le squelette récupère la valeur de retour de l'opération, la compacte
et l'envoie au talon via les éléments de communication
Même si pas de valeur de retour, on renvoie quelque chose au talon
pour l'informer de la fin de l'appel d'opération
9. Le talon décompacte la valeur et la retourne la valeur à la
partie client
10.L'appel de l'opération distante est terminé, la partie client
continue son exécution
Le marshalling/unmarshalling
Correspond dans le TP2 à la création et au décodage des
messages décrivant l'opération à appeler et ses paramètres
ainsi que les valeurs de retour
21
Middleware RPC/RMI
Gestion des problèmes de communication entre
partie client et servant
Problèmes potentiels
Le servant est planté ou inaccessible
La requête d'appel d'opération n'a pas été reçue coté servant
La réponse à la requête n'a pas été reçue par la partie client
L'exécution de l'opération s'est mal passée
...
En cas de problèmes, coté client, on n'a pas reçu la
réponse à la requête
Doit renvoyer la requête au serveur a priori
Mais coté serveur, si l'opération modifie un état doit éviter de
rappeller l'opération a priori
Plusieurs cas possibles pour gérer cela
22
Middleware RPC/RMI
4 sémantiques possibles pour l'appel d'opérations
« Peut-être »
On ne sait pas si l'opération a été appelée
« Au moins une fois »
L'opération a été appelée au moins une fois mais peut-être
plusieurs fois également
Problème si opération modifie un état (opération non idempotente)
« Au plus une fois »
L'opération est appelée une seule fois ou on reçoit un message
informant qu'un problème a eu lieu et que l'opération n'a pas été
appelée
« Une fois »
Cas idéal mais difficile à atteindre
23
Middleware RPC/RMI
Trois caractéristiques pour gérer les requêtes
d'appels d'opérations
Retransmission de la requête
Le client peut redemander au serveur d'appeler l'opération en
cas de non réponse reçue de sa part
Filtrage des duplicats de requêtes
Si le serveur détecte qu'il s'agit d'une redemande d'appel
d'opération, il n'exécute pas une nouvelle fois l'opération
Retransmission des résultats
Le serveur garde un historique des valeurs de retour des
opérations et peut renvoyer le résultat retourné pour une
opération en cas de nouvelle demande de cette même opération
24
Middleware RPC/RMI
Trois combinaisons principales de caractéristiques
et sémantiques associées
Pas de retransmission de la requête
Sémantique « peut-être »
Retransmission des requêtes mais pas de filtrage des
duplicats de requêtes
Sémantique « au moins une fois »
Retransmission des requêtes, filtrage des duplicats de
requêtes et utilisation de l'historique des réponses
Sémantique « au plus une fois »
25
Garbage collector distribué
Dans la plupart des mises en oeuvre de langages
objets : garbage collector
« Ramasse miette » en français
But : supprimer de la mémoire locale (du programme, de
la JVM en Java) les objets n'étant plus référencés par
aucun autre objet
Objets distribués (via un middleware comme Java
RMI)
Capacité à référencer des objets distants comme des
objets locaux
Pour nettoyage des objets non référencés : doit alors
prendre aussi en compte les références distantes
Distributed Garbage Collector (DGC) 26
Garbage collector distribué
Fonctionnement général d'un garbage collector (en
local)
Un compteur de référence est associé à chaque objet
Quand un objet récupère une référence sur l'objet, on
incrémente de 1 le compteur de cet objet
Quand un objet ne référence plus l'objet, on décrémente le
compteur de 1
Quand compteur a pour valeur 0, on peut supprimer l'objet
de la mémoire car plus aucun objet ne l'utilise plus
En distribué peut utiliser un fonctionnement similaire
En prenant en compte à la fois les références locales et
distantes
27
Garbage collector distribué
Contraintes supplémentaires en distribué
Coordination entre garbages collectors sur chaque
machine pour assurer gestion des références
Référence sur un objet distant = référence locale sur un proxy
pour cet objet
Quand localement un proxy n'est plus référencé par aucun objet,
on peut informer le GC gérant l'objet distant de la perte de
référence
Si une machine distante est plantée ou est inaccessible
Ne pourra pas préciser à un GC que l'objet n'est plus référencé
Solution : utiliser une durée de bail (lease)
Si au bout d'un certain temps, un objet distant n'a pas utilisé un
objet local, localement, on considère que l'objet distant ne
référence plus l'objet local
28
Java RMI
29
Java RMI
Java intègre en natif deux middlewares de type RPC/RMI
Java RMI
Une mise en oeuvre de CORBA
Java RMI
Spécifique au langage Java : ne fait communiquer que
des éléments écrits en Java
Suit l'architecture et les règles de fonctionnement des
middlewares de type RPC/RMI
Cas particulier du squelette coté serveur : depuis Java
1.2, plus besoin de squelette
L'appel de l'opération est fait via une invocation dynamique
Plus besoin d'identifier la méthode à appeler en décodant les données
reçues (comme on le faisait dans le TP4 avec décodage des
messages) 30
Java RMI
Package [Link] et sous-packages
Packages contenant les classes à utiliser ou spécialiser
pour des communications via RMI
Règles principales à suivre
Une interface d'opérations appelables à distance doit
spécialiser l'interface [Link]
Une opération de cette interface doit préciser dans sa
signature qu'elle peut lever l'exception
RemoteException
Le servant implémente une interface spécialisant Remote
et doit spécialiser (ou utiliser des services de)
UnicastRemoteObject
Les classes des données en paramètres ou retour des
opérations doivent implémenter Serializable 31
Interface
Contraintes sur interface d'opérations
Spécialise [Link] : précise qu'il s'agit d'une
interface de service appelables à distance
Chaque opération doit préciser dans sa signature qu'elle peut
lever l'exception RemoteException
L'opération peut également lever des exceptions spécifiques à l'application
RemoteException est la classe mère d'une hiérarchie d'une
vingtaine d'exceptions précisant un problème lors de l'appel de
l'opération, comme, par exemple
NoSuchObjectException : ne peut récupérer la ref sur l'objet distant
StubNotFoundException : un stub correct n'a pas été trouvé
UnknowHostException : la machine distante n'a pas été trouvée
AlreadyBoundException : le nom associé à l'objet est déjà utilisé
ConnectException : connexion refusée par la partie serveur
Pour plus d'informations sur l'exception : opération
getCause() de RemoteException 32
Exemple d'interface
Exemple d'interface, définissant 2 opérations
public interface IRectangle extends Remote {
41
Exemple coté client
Code client client pour appeler les opérations distantes
(exceptions à gérer en plus)
Rectangle r1, r2;
r1 = new Rectangle(10, 10, 20, 30);
42
Exemple coté client
Résultat du lookup
Si objet trouvé par le registry distant, retourne un objet
implémentant l'interface générique Remote
En pratique ici : un objet implémentant IRectangle
Comme par exemple RectangleImpl instantiée coté serveur
On récupère en fait une référence sur une instance de
RectangleImpl_Stub
Le talon local coté client qui sert de proxy pour l'accès à l'instance de
RectangleImpl coté serveur
Pour simplifier, on fait le cast avec IRectangle
Pas besoin de savoir l'instance de quelle classe exactement on
manipule
43
Passage des paramètres/données
Lors d'appel de méthodes distantes : 4 cas pour
gérer les paramètres ou la valeur retournée selon la
classe du paramètre
Si classe implémente Remote : passage par adresse
On passe ou récupère la référence sur un objet distant
Si classe n'implémente pas Remote : passage par valeur
L'objet est cloné, on passe ou récupère une copie de l'objet
Pour types primitifs : passage par valeur également
Si classe n'implémente pas Serializable : objet ne peut pas
être paramètre ou la classe ne peut pas être un type de retour
Les paramètres ou valeurs de retour sont forcément sérialisés
pour être transmis via le réseau (via des sockets)
44
Appels en retour
On a vu dans l'exemple précédent
Une partie client appelant une méthode sur une partie
serveur
Mais 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
Note sur les termes partie serveur et partie client
Différence entre appelant et appelé de l'opération
Chaque élément peut jouer les 2 rôles indifféremment
45
Appels en retour
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
Interface d'opérations, coté observateur
Une opération qui sera appelée par l'observée quand la
donnée observée (un entier ici) changera de valeur
public interface IChangeValue extends Remote {
47
Appels en retour
Implémentation de l'observateur
public class Observer extends UnicastRemoteObject
implements IChangeValue {
// donnée observée
protected int value = 0;
51
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é
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é 52
Appels concurrents d'opérations
Les méthodes de l'observateur sont marquées avec
synchronized
Pour éviter des incohérences en cas d'appels concurrents
Coté servant
En interne de RMI, une opération invoqueé
dynamiquement ou par le squelette 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
53
Mobilité de code
Référence sur un objet distant
En réalité une référence sur un stub local qui implémente
la même interface d'opérations que l'objet distant
Même si la classe du stub n'apparaît pas explicitement
dans le code, elle doit pouvoir être retrouvée à l'exécution
Contraintes d'une application distribuée
Les différents objets ne s'exécutent pas dans les mêmes JVM ni
sur les mêmes machines : accès aux .class peuvent différer
Malgré cela, on doit pouvoir coté client récupérer la classe du stub
2 modes pour récupérer la classe du stub de l'objet distant
Localement, la classe se retrouve via le CLASSPATH
A distance, en téléchargeant la classe à partir d'un
emplacement précisé
54
Mobilité de code
Une propriété de Java permet de préciser une URL
où aller télécharger les classes requises
[Link], à positionner en lançant
le programme Java
URL est de type « file », « ftp » ou « http »
Exemples
$ java -[Link]=[Link]
ecariou/test-rmi/ Serveur
$ java -[Link]=[Link]
[Link]/~ecariou/test-rmi/ Serveur
Problème potentiel du téléchargement de code
Sécurité : ne doit pas pouvoir par défaut télécharger n'importe
quelle classe de n'importe où
55
Mobilité de code
Gestion de la sécurité
Il n'est pas possible de télécharger des classes sans
mettre en place un « security manager »
Classe [Link]
Permet de préciser les permissions pour l'accès aux fichiers, au
réseau, à la réflexion sur les objets, à la sérialisation ...
Classe à spécialiser pour préciser les permissions selon le
contexte
Pour RMI, il existe une spécialisation :
[Link]
Très restrictif par défaut : interdit notamment le téléchargement
de classe et à peu près tout le reste aussi ...
56
Mobilité de code
Gestion de la sécurité (suite)
Avec RMI, deux façons « d'ouvrir » les restrictions
Utiliser une spécialisation « maison » de SecurityManager à la place de
RMISecurityManager
Utiliser RMISecurityManager avec en plus un fichier décrivant la
politique de permissions : fichier « policy »
Exemple, en donnant toutes les permissions
A éviter en pratique si on veut bien gérer l'aspect sécurité !
Fichier [Link]
grant {
permission [Link];
};
Spécialisation de SecurityManager
60
Mobilité de code
Mobilité de code
Ne concerne pas que les stubs
Toute classe nécessaire au bon fonctionnement de
l'application peut-être téléchargée au besoin
Exemple : variante de l'exemple avec les rectangles
La classe Rectangle2 spécialise Rectangle
public class Rectangle2 extends Rectangle {
61
Mobilité de code
Exemple (suite)
L'interface est inchangée : IRectangle
Coté servant, on modifie decaleRectangle() pour
renvoyer une instance de Rectangle2
(...)
62
Mobilité de code
Exemple (suite)
La partie client ([Link]) va télécharger les classes
dynamiquement
Elle doit donc positionner un security manager pour commencer
64
Mobilité de code
Exemple (fin)
Les classes RectangleImpl et Rectangle2 ont donc été
récupérées par le client en les téléchargeant à l'URL
[Link]
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 coté serveur : le registry n'arrive pas à récupérer le
stub, le codebase a été oublié coté serveur
65
Mobilité de code
En conclusion, pour bien gérer l'accès aux classes,
2 grands modes
S'arranger pour qu'à la fois le client et le serveur aient
accès à toutes les classes via leur CLASSPATH
Lancer systématiquement le serveur avec le codebase et
le client avec un sécurity manager pour pouvoir
télécharger les classes au besoin
En lançant le registry sans qu'il ait directement accès aux classes
Note
Ne pas oublier de prendre en compte les packages
Et donc de remonter éventuellement dans l'arborescence pour
préciser le codebase
66
Garbage collector
Java RMI gère un garbage collector distribué
En local, pour effectuer des actions avant la destruction
d'un objet
Redéfinition de la méthode finalize() de [Link]
Pour la gestion des références distantes
Interface [Link] définissant :
public void unreferenced()
Cette interface peut être implémentée par un objet offrant des
opérations appellables à distance
L'opération unreferenced est appelée quand plus aucun objet
distant ne possède de référence sur l'objet courant
Ce que l'on peut faire par exemple dans cette méthode :
« désexporter » l'objet : unexporteObject(this, true);
67
Garbage collector
Le garbage collector distribué de RMI gère une
durée de bail
Propriété [Link]
Le bail est de 10 minutes par défaut
Pour le modifier, on peut le faire au lancement du
programme
$ java -[Link]=20000 Serveur
La durée est précisée en milli-secondes, 20 secondes donc ici
Note
Ne pas oublier que le registry possède aussi une
référence sur l'objet si ce dernier a été enregisté dans le
registry
68
Exportation de l'objet
Pour exporter un objet, on a vu la classe
UnicastRemoteObject
L'objet reste alors actif et accessible en permanence
Si la JVM dans lequel il s'exécute est arrêtée, l'objet
disparaît et sa référence également
Variante possible : Activable
Permet de n'activer l'objet que quand il est sollicité
Via un mécanisme et une JVM particulers
Permet de limiter le nombre d'objets actifs en même
temps : gain de mémoire au besoin
Plus complexe à utiliser : voir documentation spécialisée
69
Gestion des firewalls
Elément important dans la construction de toute
application distribuée
Prendre en compte les éventuels firewalls pouvant
empêcher des communications à distances
Plusieurs solutions en RMI, dont l'encapsulation
des communications dans des paquets HTTP
Tunneling HTTP
Evite le filtrage sur les ports « non standards »
Voir documentation spécialisées pour plus d'infos
70