Introduction à Java RMI et Callback
Introduction à Java RMI et Callback
Damien Pellier (MASTER I Info.) Applications Distribuées 97 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 98 / 430
Rappel des conclusions sur l’appel de procédure à distance Intérêt des objets pour la construction d’applications
Avantages réparties
Abstraction (les détails de la communication sont cachés)
Intégration dans un langage : facilite portabilité, mise au point
Outils de génération, facilitent la mise en œuvre Encapsulation
! L’interface (méthodes + attributs) est la seule voie d !accès à l’état interne,
non directement accessible
Limitations Classes et instances
La structure de l’application est statique : pas de création dynamique de ! Mécanismes de génération d’exemplaires conformes à un même modèle
serveur, pas de possibilité de redéploiement entre sites
Héritage
Pas de passage des paramètres par référence ! Mécanisme de spécialisation : facilite récupération et réutilisation de l’existant
La communication est réduite à un schéma synchrone Polymorphisme
La persistance des données n’est pas assurée (il faut la réaliser explicitement ! Mises en oeuvre diverses des fonctions d’une interface
par sauvegarde des données dans des fichiers) ! Remplacement d’un objet par un autre si interfaces « compatibles »
! Facilite l’évolution et l’adaptation des applications
Des mécanismes plus évolués visent à remédier à ces limitations
! Objets répartis (ex : Java RMI, CORBA) pour les 2 premières
! Bus à messages (Message Oriented Middleware)
! Composants répartis (ex : EJB, Corba CCM, .Net)
Damien Pellier (MASTER I Info.) Applications Distribuées 99 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 100 / 430
Extension du RPC aux objets (1) Extension du RPC aux objets (2)
Appel de procédure vs appel de méthode sur un objet Phase préalable : création d !instances d’une classe d’objects
! Exemple : insérer une entrée dans un annuaire ! Notion de fabrique (factory)
! Notion de référence d’objet
" Contient tout ce qui est nécessaire pour atteindre l’objet distant, i.e.,
Client Serveur
Localisation, protocole d’accès
Appel de procédure
exécuter
Inserer(nom, numero) Insérer Client Serveur
fabrique
Créer(annuaire_1, params) d'annuaires
exécuter
Ref. sur annuaire_1
créer
Client Serveur Créer(annuaire_2, params)
Ref. sur annuaire_2
Appel d'objet annuaire_1
Insérer(nom, numéro) exécuter annuaire_1 annuaire_2
Insérer annuaire_2
dans annuaire_1
[...] exécuter
Insérer
Insérer(nom, numéro)
dans annuaire_2
Appel d'objet
Damien Pellier (MASTER I Info.) Applications Distribuées 101 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 102 / 430
2 cf. [Link]
Damien Pellier (MASTER I Info.) Applications Distribuées 103 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 104 / 430
Java RMI : règles d’usage Java RMI : règles d’écriture du serveur
Interface
! L’interface d’un objet distant (Remote) est celle d’un objet Java, avec
quelques règles d’usage :
1 L’interface distante doit être publique
2 L’interface distante doit étendre l’interface [Link] Un serveur est une classe qui implémente l’interface de l’objet distant
3 Chaque méthode doit déclarer au moins l’exception
[Link]
1 Spécifier les références distantes qui doivent être implémentées (objets passés
en paramètres)
Passage d’objets en paramètre 2 Définir le constructeur de l’objet distant
! Les objets locaux sont passés par valeur (copie) et doivent être sérialisables 3 Fournir la réalisation des méthodes appelables à distance
(étendent l’interface [Link]) 4 Créer et installer le gestionnaire de sécurité
! Les objets distants sont passés par référence et sont désignés par leur interface 5 Créer au moins une instance de la classe serveur
Réalisation des classes distantes (Remote) 6 Enregistrer au moins une instance dans le serveur de noms
! Une classe distante doit implémenter une interface elle-même distante
(Remote)
! Une classe distante doit étendre la classe
[Link] (d’autres possibilités existent)
! Une classe distante peut aussi avoir des méthodes appelables seulement
localement (ne font pas partie de son interface Remote)
Damien Pellier (MASTER I Info.) Applications Distribuées 105 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 106 / 430
Java RMI : exemple (Hello world) Java RMI : exemple (Hello world)
Classe réalisant l’interface
import java . rmi . RemoteException ;
Définition d’interface import java . rmi . s e r v e r . UnicastRemoteObject ;
public c l a s s Hello extends UnicastRemoteObject implements H e l l o I n t e r f a c e {
import java . rmi . Remote ; /∗∗ Message p ré dé f i n i ∗/
import java . rmi . RemoteException ; private String message ;
/∗∗
public i n t e r f a c e H e l l o I n t e r f a c e extends Remote { ∗ Créer un nouvel objet <code>Hello</code>.
∗ @param s l e message p ré dé f i n i dans <code>Hello</code>.
/∗∗ ∗/
∗ Méthode qui imprime un message p ré dé f i n i dans l ’ objet public Hello ( String s ) throws RemoteException {
∗ appelé . message = s ;
∗ @return un message p ré dé f i n i . }
∗ @throws RemoteException s i une e r r e u r se produit au
∗ cours de l ’ appel de méthode /∗∗
∗/ ∗ Implémentation de l a méthode <code>sayHello()</code>.
public String sayHello ( ) throws RemoteException ; ∗ @return p ré dé f i n i dans <code>Hello</code>.
} ∗ @throws RemoteException s i une e r r e u r se produit .
∗/
public String sayHello ( ) throws RemoteException {
return message ;
}
}
Damien Pellier (MASTER I Info.) Applications Distribuées 107 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 108 / 430
Java RMI : exemple (Hello world) Java RMI : exemple (Hello world)
Damien Pellier (MASTER I Info.) Applications Distribuées 109 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 110 / 430
Java RMI : Étapes de la mise en œuvre (1) Java RMI : Étapes de la mise en œuvre (2)
Exécution
Compilation 1 Lancer le serveur de noms (sur la machine serveur)
1 Sur la machine serveur : compiler les interfaces et les programmes du serveur
> rmiregistry &
> javac [Link] [Link] [Link]
N.B. Par défaut, le registry écoute sur le port 1099. Si on veut le placer sur un
2 Sur la machine serveur : créer les talons client et serveur pour les objets autre port, il suffit de l’indiquer, mais il faut aussi modifier les URL en
appelés à distance (à partir de leurs interfaces) - ici une seule classe, Hello conséquence : rmi ://<serveur> :<port>/<répertoire>
2 Lancer le serveur
> rmic -keep Hello
> java -[Link]=http ://[Link]/<répertoire des classes>
N.B. cette commande construit et compile les talons client Hello [Link] -[Link]=[Link] HelloServeur &
et serveur Hello [Link]. L’option -keep permet de garder les sources de
ces talons. N.B. Signification des propriétés (option -D) :
" Le contenu du fichier [Link] spécifie la politique de sécurité, cf. plus loin.
3 Sur la machine client : compiler les interfaces et le programme client " L’URL donnée par codebase sert au chargement de classes par le client
> javac [Link] [Link] 3 Lancer le client
N.B. il est préférable de regrouper dans un fichier .jar les interfaces des objets > java -[Link]=[Link] HelloClient
appelés à distance, ce qui permet de les réutiliser pour le serveur et le client
N.B. Le talon client sera chargé par le client depuis le site du serveur, spécifié
dans l’option codebase.
Damien Pellier (MASTER I Info.) Applications Distribuées 111 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 112 / 430
Sécurité Fonctionnement d’ensemble de Java RMI
! Permet d’utiliser les sockets comme indiqué. Toute autre utilisation est
interdite 5. appel
Damien Pellier (MASTER I Info.) Applications Distribuées 113 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 114 / 430
Damien Pellier (MASTER I Info.) Applications Distribuées 115 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 116 / 430
Fabrique d’objets : exemple « l’annuaire » Fabrique d’objets : exemple « l’annuaire »
Les classes annexes L’implémentation de l’annuaire
Damien Pellier (MASTER I Info.) Applications Distribuées 117 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 118 / 430
Classe AnnuaireImpl
Classe FabriqueAnnuaireImpl
public boolean supprimer ( String nom ) throws RemoteException , PasTrouve {
i f ( t h i s . annuaire . get ( nom ) == n u l l ) {
throw new PasTrouve ( ) ; import java . rmi . s e r v e r . UnicastRemoteObject ;
} else { import java . rmi . RemoteException ;
t h i s . annuaire . remove ( nom ) ;
} public c l a s s FabriqueAnnuaireImpl extends UnicastRemoteObject
return true ; implements FabriqueAnnuaire {
}
public I n f o rechercher ( String nom ) throws RemoteException , PasTrouve { public FabriqueAnnuaireImpl ( ) throws RemoteException {}
i f ( t h i s . annuaire . get ( nom ) == n u l l ) {
throw new PasTrouve ( ) ; public Annuaire newAnnuaire ( String t i t r e ) throws RemoteException {
} else { return new AnnuaireImpl ( t i t r e ) ;
return t h i s . annuaire . get ( nom ) ; }
} }
}
}
Damien Pellier (MASTER I Info.) Applications Distribuées 119 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 120 / 430
Fabrique d’objets : exemple « l’annuaire » Fabrique d’objets : exemple « l’annuaire »
Le serveur d’annuaires Le client d’annuaires
Classe AnnuaireClient
Classe AnnuaireServeur import java . lang . Exception ;
import java . rmi . Naming ;
import java . rmi . RMISecurityManager ;
import java . lang . Exception ; public c l a s s AnnuaireClient {
import java . rmi . Naming ; public s t a t i c void main ( String [ ] argv ) {
import java . rmi . RMISecurityManager ; /∗ l a n c e r SecurityManager ∗/
System . setSecurityManager ( new RMISecurityManager ( ) ) ;
public c l a s s AnnuaireServeur { try {
/∗ trouver une ré fé r e n c e ve rs l a fa brique ∗/
public s t a t i c void main ( String [ ] argv ) { FabriqueAnnuaire fa bri que =
( FabriqueAnnuaire ) Naming . lookup ( ”rmi :// p a r i s 5 . f r /Fabrique” ) ;
/∗ l a n c e r SecurityManager ∗/
System . setSecurityManager ( new RMISecurityManager ( ) ) ; /∗ c ré e r un annuaire ∗/
try { Annuaire annuaire 1 = fa brique . newAnnuaire ( ”Annuaire 1” ) ;
Naming . rebind ( ”Fabrique” , new FabriqueAnnuaireImpl ( ) ) ; /∗ c ré e r un autre annuaire ∗/
System . out . p r i n t l n ( ”Serveur prêt . ” ) ; Annuaire annuaire 2 = fabrique . newAnnuaire ( ”Annuaire 2” ) ;
} catch ( Exception e ) { /∗ u t i l i s e r l e s annuaires ∗/
System . out . p r i n t l n ( ”Erreur serveur : ” + e ) ; annuaire 1 . i n s e r e r ( ” L i s e ” , new I n f o ( ” Paris ” , ”0678654543” ) ) ;
} annuaire 2 . i n s e r e r ( ”Rémi” , new I n f o ( ”Bordeaux” , ”0612763490” ) ) ;
} } catch ( Exception e ) {
} System . out . p r i n t l n ( ”Erreur c l i e n t : ” + e ) ;
}
}
}
Damien Pellier (MASTER I Info.) Applications Distribuées 121 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 122 / 430
annuaire_1.inserer(...)
annuaire_2.recherche(...)
Damien Pellier (MASTER I Info.) Applications Distribuées 123 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 124 / 430
Passage d’objets en paramètre (2) Passage d’objets en paramètre (3)
Illustration
Notions sur les objets sérialisables
! Un objet sérialisable (transmissible par valeur hors de sa JVM) doit
Le stub est transmis en
parmètre à la place de l'objet implémenter l’interface [Link]. Celle-ci est réduite à un
distant annuaire_1 repertoireCentral
marqueur (pas de variables ni d’interface)
! Les objets référencés dans un objet sérialisable doivent aussi être sérialisables
! Comment rendre effectivement un objet sérialisable ?
stub
1 Pour les variables de types primitifs (int, boolean, etc.), rien à faire
2 Pour les objets dont les champs sont constitués de telles variables : rien à faire
3 On peut éliminer une variable de la représentation sérialisée en la déclarant
transient
stub Une copie sérialisée
4 Pour un champ non immédiatement sérialisable, e.g., Array, il faut fournir des
de l'objet local info1 annuaire_1 fabrique méthodes readObject() et writeObject()
est transmise
...
[Link](annuaire_1)
annuaire_1.inserer(nom1,info1)
Exemples de sérialisation : écriture dans un fichier
Le support de sérialisation est un stream (flot) classes :
annuaire_2
stub stub [Link]
[Link]
Pour des détails techniques voir le javadoc.
Damien Pellier (MASTER I Info.) Applications Distribuées 125 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 126 / 430
Notions sur le fonctionnement interne de Java RMI (1) Notions sur le fonctionnement interne de Java RMI (2)
La classe UnicastRemoteObject
!
Le serveur de noms (registry)
Rappel de la règle d’usage : une classe d’objets accessibles à distance étend la
! Classes utiles (fournies par [Link])
classe [Link]
" Naming : sert de représentant local du serveur de noms. Permet d’utiliser les
" La principale fonction de cette classe se manifeste lors de la création d’une
instance de l’objet. méthodes bind(), rebind(), lookup(), unbind(), list()
" LocateRegistry : permet de localiser un serveur de noms (rmiregistry) et
éventuellement d’en créer un. En général invisible au client (appelé en interne
Classe AnnuaireImpl par Naming)
public c l a s s AnnuaireImpl extends UnicastRemoteObject {
AnnuaireImpl ( . . . ) {} // AnnuaireImpl () a p p e l l e automatiquement l e
// constructeur de l a s u p e r c l a s s e UnicastRemoteObject Site Client Site Serveur
...
monAnnuaire = new AnnuaireImpl ( . . . ) ;
Programme Client Naming Registry
" Le constructeur de UnicastRemoteObject crée une instance de stub pour
l’objet (en utilisant la classe Annuaire Stub engendrée par rmic, et retourne ce getRegistery()
renvoie une
stub comme résultat de la création bind(), unbind(), rebind(), référence de l'objet
lookup(), list() registery
Le contenu d’un stub
! Un stub contient essentiellement une variable ref de type RemoteRef qui LocalRegistry
contient la localisation de l’objet (adresse IP, port)
! Un appel de méthode se fait par appel de [Link](...) qui utilise les
sockets pour la communication
Damien Pellier (MASTER I Info.) Applications Distribuées 127 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 128 / 430
Appel en retour (callback) Appel en retour (callback)
Principe
Le client passe en paramètre au serveur l’objet à rappeler
Le serveur exécute un appel asynchrone sur cet objet
Le problème
Site Client Site Serveur
! Réaliser un appel du serveur vers le client
Intérêt Serveur
! Augmenter l’asynchronisme
1 appel client-serveur avec retour immédiat (demande service)
2 rappel serveur-client quand le service est exécuté créer
! Augmenter le dynamisme
Interface
" Le serveur peut demander des informations complémentaires au client en cours Serveur
créer Servant
d’exécution
" L’exécution du service peut faire appel à des services fournis par le client, e.g., Callback
run
traitement d’exceptions
doCallback
thread
séparé
Interface (pour servir clients
Callback multiples)
Damien Pellier (MASTER I Info.) Applications Distribuées 129 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 130 / 430
Class Servant
Définition de l’interface Callback import java . rmi . ∗ ;
public c l a s s Servant extends Thread {
import java . rmi . Remote ; private i n t time ;
import java . rmi . RemoteException ; private String param ;
private I n t e r f a c e C a l l b a c k c a l l b a c k ;
public i n t e r f a c e I n t e r f a c e C a l l b a c k extends Remote { public Servant ( i n t time , String param , I n t e r f a c e C a l l b a c k c a l l b a c k ) {
public void doCallback ( String message ) throws RemoteException ; t h i s . time = time ;
} t h i s . param = param ;
this . callback = callback ;
}
public void run ( ) { // exécution du servant comme thread séparé
Définition de l’interface Serveur try {
Thread . s l e e p ( 1 00 0 ∗ time ) ; // attend l e dé l a i f i x é
import java . rmi . Remote ∗ ; } catch ( InterruptedException e ) { } // ( time exprimé
import java . rmi . RemoteException ; try { // en secondes )
c a l l b a c k . doCallback ( param ) ; // exécute l ’ appel en retour
public i n t e r f a c e I n t e r f a c e S e r v e r extends Remote { } catch ( RemoteException e ) {
public void callMeBack ( i n t time , String param , I n t e r f a c e C a l l b a c k c a l l b a c k ) System . e r r . p r i n t l n ( ”Echec appel en retour : ” + e ) ;
throws RemoteException ; }
}
c a l l b a c k = n u l l ; // nettoyage
System . gc ( ) ;
}
Rappel : les objets appelés à distance doivent étendre Remote }
Damien Pellier (MASTER I Info.) Applications Distribuées 131 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 132 / 430
Appel en retour (callback) Appel en retour (callback)
Réalisation du serveur Réalisation de l’appel en retour
Class CallbackServeur
import java . lang . Exception ;
import java . rmi . Naming ; Class Callback
import java . rmi . RemoteException ;
import java . rmi . s e r v e r . UnicastRemoteObject ; import java . rmi . RemoteException ;
public c l a s s CallbackServer extends UnicastRemoteObject { import java . rmi . s e r v e r . UnicastRemoteObject ;
public CallbackServer ( ) throws RemoteException {
super ( ) ; public c l a s s Callback extends UnicastRemoteObject
} implements I n t e r f a c e C a l l b a c k {
public void callMeBack ( i n t time , String param , I n t e r f a c e C a l l b a c k c a l l b a c k )
throws RemoteException { public Callback ( ) throws RemoteException {
// Création du servant super ( ) ;
Servant servant = new Servant ( time , param , c a l l b a c k ) ; }
servant . s t a r t ( ) ; // démarrage du servant
} public void doCallback ( String message ) throws RemoteException {
public s t a t i c void main ( String [ ] args ) throws Exception { System . out . p r i n t l n ( message ) ;
}
// démarrage du serveur }
Server serveur = new Server ( ) ;
Naming . rebind ( ”Server” , serveur ) ;
System . out . p r i n t l n ( ”Serveur pret ” ) ;
}
}
Damien Pellier (MASTER I Info.) Applications Distribuées 133 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 134 / 430
Class CallbackClient
Extension du RPC aux objets
import java . lang . Exception ;
! Permet l’accès à des objets distants
import java . lang . InterruptedException ;
import java . rmi . Naming ; ! Permet d’étendre l’environnement local par chargement dynamique de code
! Pas de langage séparé de description d’interfaces (IDL fourni par Java)
public c l a s s C l i e n t {
Limitations
public s t a t i c void main ( String [ ] args ) throws Exception {
! Environnement restreint à un langage unique (Java)
Callback c a l l b a c k = new Callback ( ) ; // c ré a t i o n de l ’ objet c a l l b a c k
I n t e r f a c e S e r v e r serveur = ( I n t e r f a c e S e r v e r ) Naming . lookup ( ”Server” ) ; " Mais passerelles possibles, en particulier RMI/IIOP
System . out . p r i n t l n ( ”démarrage de l ’ appel” ) ; ! Services réduits au minimum
serveur . callMeBack ( 5 , ”coucou” , c a l l b a c k ) ; // demande de rappel "
f o r ( i n t i =; i <=5; i ++) { Service élémentaire de noms (sans attributs)
" Pas de services additionnels :
System . out . p r i n t l n ( i ) ;
try { → Duplication d’objets
Thread . s l e e p ( 2 0 0 0 ) ; → Transactions
} catch ( InterruptedException e ) { } → etc.
}
System . out . p r i n t l n ( ” f i n du main” ) ;
}
}
Damien Pellier (MASTER I Info.) Applications Distribuées 135 / 430 Damien Pellier (MASTER I Info.) Applications Distribuées 136 / 430