Vous êtes sur la page 1sur 7

Master Informatique M1

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
Introduction aux objets répartis ■ Classes et instances
Java RMI ◆ 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
Sacha Krakowiak
Université Joseph Fourier ■ Polymorphisme
Projet Sardes (INRIA et IMAG-LSR)
◆ Mises en œuvre diverses des fonctions d’une interface
http://sardes.inrialpes.fr/people/krakowia ◆ Remplacement d’un objet par un autre si interfaces “compatibles”
◆ Facilite l’évolution et l’adaptation des applications

© 2003-2004, S. Krakowiak 2

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)

Appel de procédure
exécuter fabrique
inserer (nom, numero) insérer créer (annuaire_1, params) d’annuaires
exec.
ref. sur annuaire_1 créer
créer (annuaire_2, params)
client serveur ref. sur annuaire_2 new
new
Appel d’objet annuaire_1 annuaire_2 annuaire_1
inserer (nom, numero) exec. client annuaire_2
dans annuaire_1 insérer
[…] exec.
insérer Notion de référence d’objet
Appel d’objet Contient tout ce qui est nécessaire
inserer (nom, numero) pour atteindre l’objet distant
dans annuaire_2 Localisation, protocole d’accès

serveur
client serveur

© 2003-2004, S. Krakowiak 3 © 2003-2004, S. Krakowiak 4


Java RMI (Remote Method Invocation) Java RMI : règles d’usage (1/2)

■ Motivation : construction d’applications réparties avec Java


◆ Appel de méthode au lieu d’appel de procédure ■ Interface
■ Principe : même schéma que RPC ◆ L’interface d’un objet distant (Remote) est celle d’un objet
Java, avec quelques règles d’usage :
◆ Le programmeur fournit
❖ Une (ou plusieurs) description(s) d’interface
◆ L’interface distante doit être publique
▲ Ici pas d’IDL séparé : Java sert d’IDL ◆ L’interface distante doit étendre l’interface java.rmi.Remote
❖ Le programme du serveur ◆ Chaque méthode doit déclarer au moins l’exception
▲ Objets réalisant les interfaces
java.rmi.RemoteException
▲ Serveur ■ Passage d’objets en paramètre
❖ Le programme du client ◆ Les objets locaux sont passés par valeur (copie) et doivent
◆ L’environnement Java fournit être sérialisables (étendent l’interface java.io.Serializable)
❖ Un générateur de talons (rmic) ◆ Les objets distants sont passés par référence et sont
❖ Un service de noms (Object Registry) désignés par leur interface

voir http://java.sun.com/docs/books/tutorial/rmi/

© 2003-2004, S. Krakowiak 5 © 2003-2004, S. Krakowiak 6

Java RMI : règles d’usage (2/2) Java RMI : règles d’écriture du serveur

■ Réalisation des classes distantes (Remote)


◆ Une classe distante doit implémenter une interface elle-même
■ Un serveur est une classe qui implémente
distante (Remote) l’interface de l’objet distant
◆ Une classe distante doit étendre la classe ◆ Spécifier les références distantes qui doivent être
java.rmi.server.UnicastRemoteObject (d’autres possibilités implémentées (objets passés en paramètres)
existent) ◆ Définir le constructeur de l’objet distant
◆ Une classe distante peut aussi avoir des méthodes appelables ◆ Fournir la réalisation des méthodes appelables à distance
seulement localement (ne font pas partie de son interface Remote) ◆ Créer et installer le gestionnaire de sécurité
◆ Créer au moins une instance de la classe serveur
◆ Enregistrer au moins une instance dans le serveur de noms

© 2003-2004, S. Krakowiak 7 © 2003-2004, S. Krakowiak 8


Java RMI : exemple (Hello world) Java RMI : exemple (Hello world)

Programme du client Programme du serveur


Classe réalisant l’interface
import java.rmi.*;
import java.rmi.*;
public class HelloClient {
import java.rmi.*; public class HelloServer {
public static void main (String [ ] argv) {
Définition d’interface import java.rmi.server.*; public static void main (String [ ] argv) {
public class Hello /* lancer SecurityManager */
extends java.rmi.server.UnicastRemoteObject /* lancer SecurityManager */
import java.rmi.*; implements HelloInterface {
public interface HelloInterface System.setSecurityManager (
private String message; System.setSecurityManager (
extends Remote { new RMISecurityManager ()) ;
new RMISecurityManager ()) ;
/* le constructeur */ try {
/* méthode qui imprime un message public Hello (String s) try {
prédéfini dans l’objet appelé */ throws RemoteException /* trouver une référence vers l’objet distant */
{ /* créer une instance de la classe Hello et
public String sayHello () HelloInterface hello =
message = s ; l’enregistrer dans le serveur de noms */
throws java.rmi.RemoteException; (HelloInterface) Naming.lookup
}; Naming.rebind ("Hello1”,
} ("rmi://goedel.imag.fr/Hello1") ;
new Hello ("Hello world !")) ;
/* l’implémentation de la méthode */ System.out.println ("Serveur prêt.") ;
/* appel de méthode à distance */
public String sayHello () System.out.println (hello.sayHello()) ;
throws RemoteException } catch (Exception e) {
{ System.out.println
} catch (Exception e) {
return message ; ("Erreur serveur : " + e) ;
System.out.println
}; }
("Erreur client : " + e) ;
}
}
}
}
} }

© 2003-2004, S. Krakowiak 9 © 2003-2004, S. Krakowiak 10

Java RMI : Étapes de la mise en œuvre (1/2) Java RMI : Étapes de la mise en œuvre (1/2)

■ Compilation ■ Exécution
◆ Sur la machine serveur : compiler les interfaces et les programmes du serveur ◆ Lancer le serveur de noms (sur la machine serveur)
rmiregistry &
javac HelloInterface.java Hello.java HelloServer.java
◆ Sur la machine serveur : créer les talons client et serveur pour les objets appelés N.B. Par défaut, le registry écoute sur le port 1099. Si on veut le placer sur un autre port, il suffit
à distance (à partir de leurs interfaces) - ici une seule classe, Hello de l’indiquer, mais il faut aussi modifier les URL en conséquence :
rmi://<serveur>:<port>/<répertoire>
rmic -keep Hello ◆ Lancer le serveur
N.B. cette commande construit et compile les talons client Hello_Stub.java et java -Djava.rmi.server.codebase=http://goedel.imag.fr/<répertoire des classes>
serveur Hello_Skel.java. L’option -keep permet de garder les sources de ces -Djava.security.policy=java.policy HelloServer &
talons N.B. Signification des propriétés (option -D) :
• Le contenu du fichier java.policy spécifie la politique de sécurité, cf plus loin.
• L’URL donnée par codebase sert au chargement de classes par le client
◆ Sur la machine client : compiler les interfaces et le programme client
◆ Lancer le client
javac HelloInterface.java HelloClient.java
java -Djava.security.policy=java.policy HelloClient
N.B. il est préférable de regrouper dans un fichier .jar les interfaces des objets
N.B. Le talon client sera chargé par le client depuis le site du serveur, spécifié dans l’option
appelés à distance, ce qui permet de les réutiliser pour le serveur et le client - codebase lors du lancement du serveur
voir TP

© 2003-2004, S. Krakowiak 11 © 2003-2004, S. Krakowiak 12


Sécurité Fonctionnement d’ensemble de Java RMI

■ Motivations
◆ La sécurité est importante lorsqu’il y a téléchargement de code (il peut Site
être dangereux d’exécuter le code chargé depuis un site distant) registry serveur
3. rechercher
■ Mise en œuvre objet Hello_Stub
◆ La politique de sécurité spécifie les actions autorisées, en particulier 1. créer stub
sur les sockets 2. enregistrer stub

◆ Exemple de contenu du fichier java.policy


HelloClient HelloServer Hello
grant {
permission java.net.SocketPermission "*:1024-65535",
4. télécharger
"connect,accept";
stub
permission java.net.SocketPermission "*:80", "connect";
Hello_Stub Hello_Skel
};

◆ Permet d’utiliser les sockets comme indiqué. Toute autre utilisation Site
client 5. appel
est interdite

© 2003-2004, S. Krakowiak 13 © 2003-2004, S. Krakowiak 14

Fabrique d’objets (Factory) Mise en œuvre d’une fabrique

public class AnnuaireImpl implements Annuaire


■ Motivation extends UnicastRemoteObject{ import java.rmi.*;
◆ Permettre au client de construire des instances multiples d’une classe C sur private String letitre; public class Server {
le site serveur public Annuaire(String titre) { public static void main (String [ ] argv)
this.letitre=titre}; {
◆ Le new n’est pas utilisable tel quel (car il ne gère que la mémoire locale,
public String titre {return letitre};
celle du client) /* lancer SecurityManager */
public boolean inserer(String nom, Info info)
◆ Solution : appel d’un objet FabriqueC, qui crée localement (sur le serveur) throws RemoteException, ExisteDeja{ System.setSecurityManager (
les instances de C (en utilisant new C) …}; new RMISecurityManager ()) ;
public boolean supprimer(String nom)
■ Exemple throws RemoteException, PasTrouve{ try {
import java.rmi.* …};
public interface FabAnnuaire extends Remote{ public Info rechercher(String nom) Naming.rebind ("Fabrique”,
public Annuaire newAnnuaire(String titre) throws RemoteException, PasTrouve{ new (FabAnnuaireImpl)) ;
throws RemoteException ; …}; System.out.println ("Serveur prêt.") ;
public interface Annuaire extends Remote{ } } La classe annuaire
public String titre; } catch (Exception e) {
public boolean inserer(String nom, Info info) System.out.println
throws RemoteException, ExisteDeja; public class Info implements Serializable { ("Erreur serveur : " + e) ;
public class FabAnnuaireImpl implements FabAnnuaire }
public boolean supprimer(String nom) public String adresse; extends UnicastRemoteObject{ }
throws RemoteException, PasTrouve; public int num_tel ; public FabAnnuaireImpl{}; }
public Info rechercher(String nom) } public Annuaire newAnnuaire(String titre) Le serveur
throws RemoteException, PasTrouve; public class ExisteDeja extends Exception{} ; throws RemoteException {
} public class PasTrouve extends Exception{} ; return new AnnuaireImpl(titre)};
} La classe fabrique

© 2003-2004, S. Krakowiak 15 © 2003-2004, S. Krakowiak 16


Utilisation de la fabrique Fonctionnement d’ensemble de la fabrique

Programme client
rebind(fabrique,…)
import java.rmi.*; /* utiliser les annuaires */ Registry Serveur Noter les deux manières
public class HelloClient { annuaireIMAG.inserer(…, …);
d’obtenir une référence d’objet
public static void main (String [ ] argv) { annuaireINRIA.inserer(…, …);
…. fabrique = lookup(…) créér fabrique distant
/* lancer SecurityManager */ (new) - par consultation du registry
} catch (Exception e) { - par création via une fabrique
System.setSecurityManager ( System.out.println fabrique.newAnnuaire(…)
new RMISecurityManager ()) ; ("Erreur client : " + e) ; Fabrique
} Client d’annuaires
try { } référence de l’annuaire
} créé (annuaireIMAG, …)
/* trouver une référence vers la fabrique */
FabAbannuaire fabrique =
(FabAbannuaire ) Naming.lookup
("rmi://goedel.imag.fr/Fabrique") ;

/* créer un annuaire */ Annuaire Annuaire Annuaire


annuaireIMAG = fabrique.newAnnuaire("IMAG"); INRIA IMAG
… UJF
/* créer un autre annuaire */
annuaireINRIA= fabrique.newAnnuaire("INRIA"); annuaireINRIA.inserer(…)

annuaireIMAG rechercher(…)

© 2003-2004, S. Krakowiak 17 © 2003-2004, S. Krakowiak 18

Passage d’objets en paramètre (1) Passage d’objets en paramètre : illustration

■ Deux cas possibles


◆ Passage en paramètre d’un objet local (sur la JVM de l’objet repertoireCentral
appelant) Le stub est transmis en
❖ Passage par valeur : on transmet une copie de l’objet (plus paramètre à la place de
précisément : une copie de l’ensemble ses variables d’état) l’objet distant annuaireIMAG
Pour cela l’objet doit être sérialisable (i.e. implémenter
l’interface java.io.Serializable)
❖ Exemple de l’annuaire : le client transmet un objet de la classe stub
locale Info
◆ Passage en paramètre d’un objet non-local (hors de la JVM de
Une copie sérialisée
l’objet appelant, par ex. sur un site distant) stub de l’objet local info1 Fabrique
annuaireINRIA
❖ Passage par référence : on transmet une référence sur l’objet … est transmise
(plus précisément : un stub de l’objet). Le destinataire utilisera repertoireCentral.enregistrer(annuaireIMAG)
ce stub pour appeler les méthodes de l’objet. annuaireINRIA.inserer(nom1,info1)
annuaireIMAG
❖ Exemple de l’annuaire : le client passe un objet de type
Annuaire (localisé sur le serveur distant) stub stub

© 2003-2004, S. Krakowiak 19 © 2003-2004, S. Krakowiak 20


Passage d’objets en paramètre (2) Notions sur le fonctionnement interne de Java RMI (1)

■ Notions sur les objets sérialisables ■ La classe UnicastRemoteObject


◆ Un objet sérialisable (transmissible par valeur hors de sa JVM) doit ◆ Rappel de la règle d’usage : une classe d’objets accessibles à distance
implémenter l’interface java.io.Serializable. Celle-ci est réduite à un étend la classe java.rmi.UnicastRemoteObject.
marqueur (pas de variables ni d’interface) ❖ Le principale fonction de cette classe se manifeste lors de la création
◆ Les objets référencés dans un objet sérialisable doivent aussi être d’une instance de l’objet.
sérialisables public class AnnuaireImpl extends UnicastRemoteObject {…}
◆ Comment rendre effectivement un objet sérialisable ?
AnnuaireImpl (…) { // le constructeur de C appelle automatiquement
❖ Pour les variables de types primitifs (int, boolean, …), rien à faire
// le constructeur de la superclasse UnicastRemoteObject
❖ Pour les objets dont les champs sont constitués de telles variables : …
rien à faire monAnnuaire = new AnnuaireImpl (…) ;
❖ On peut éliminer une variable de la représentation sérialisée en la
déclarant transient ❖ Le constructeur crée une instance de stub pour l’objet (en utilisant la
❖ Pour un champ non immédiatement sérialisable (ex. : Array),il faut classe Annuaire_Stub engendrée par rmic, et retourne ce stub comme
fournir des méthodes readObject() et writeObject() résultat de la création
◆ Exemples de sérialisation : passage en paramètres, écriture sur un fichier. ■ Le contenu d’un stub
Le support de sérialisation est un stream (flot) : classes
◆ Un stub contient essentiellement une variable ref de type RemoteRef qui
java.io.ObjectOutputStream et java.io.ObjectInputStream. contient la localisation de l’objet (adresse IP, port)
◆ Un appel de méthode se fait par appel de ref.invoke(…) qui utilise les
Pour des détails techniques : voir javadoc de l’interface Serializable et des
sockets pour la communication
classes ObjectOutputStream et ObjectInputStream

© 2003-2004, S. Krakowiak 21 © 2003-2004, S. Krakowiak 22

Notions sur le fonctionnement interne de Java RMI (2) Conclusion sur Java RMI

■ Le serveur de noms (registry) ■ Extension du RPC aux objets


◆ Classes utiles (fournies par java.rmi) ◆ Permet l’accès à des objets distants
❖ Naming : sert de représentant local du serveur de noms. Permet ◆ Permet d’étendre l’environnement local par chargement
d’utiliser les méthodes bind(), rebind(), lookup(), unbind(), list() dynamique de code
❖ LocateRegistry : permet de localiser un serveur de noms ◆ Pas de langage séparé de description d’interfaces (IDL fourni
(rmiregistry) et éventuellement d’en créer un. En général invisible par Java)
au client (appelé en interne par Naming)
■ Limitations
◆ Environnement restreint à un langage unique (Java)
❖ Mais passerelles possibles, en particulier RMI/IIOP
Prog. client Naming Registry
◆ Services réduits au minimum
❖ Service élémentaire de noms (sans attributs)
bind, unbind, getRegistry ❖ Pas de services additionnels
rebind, lookup, list renvoie une
référence de ▲ Duplication d’objets
l’objet registry
LocateRegistry
▲ Transactions
Site client Site serveur ▲ …

© 2003-2004, S. Krakowiak 23 © 2003-2004, S. Krakowiak 24


Compléments

Tout n’a pas été traité ici. Il reste des points complémentaires, dont certains
seront vus lors des TP

■ Parallélisme sur le serveur


◆ Un serveur RMI peut servir plusieurs clients. Dans ce cas, un
thread séparé est créé pour chaque client sur le serveur. C’est au
développeur du programme serveur d’assurer leur bonne
synchronisation (exemple : méthodes synchronized) pour garantir
la cohérence des données)
■ Activation automatique de serveurs
◆ Un veilleur (demon) spécialisé, rmid, peut assurer le lancement de
plusieurs classes serveur sur un site distant (cette opération est
invisible au client)
■ Téléchargement de code
◆ Un chargeur spécial (ClassLoader) peut être développé pour
assurer le téléchargement des classes nécessaires (cf TP)

© 2003-2004, S. Krakowiak 25

Vous aimerez peut-être aussi