Dr BOUAMAMA Samah
2016/2017 1
Sommaire
• Rappel et Limites des RPC (Remote Procedure Call)
• Principe des RMI
• Etapes de développement et d ’exécution
• Paramètres des méthodes
• Objet Activable
• Personnalisation de la couche de transport
• Aspects avancés de RMI:
2
Rappel des RPC
• RPC (Remote Procedure Call)
• modèle client/serveur
• appel de procédures à distances entre un client et un serveur
• le client appelle une procédure
• le serveur exécute la procédure et renvoie le résultat
• la souche et le squelette ouvre un socket et encode/décode les paramètres
• Couche de présentation XDR (eXchange Data Representation)
format pivot de représentation des données de types primitifs et structurés (tableau de
longueur variable, structures) quelque soit
l ’architecture (Little Endian/Big Endian, IEEE, …)
le langage (ordre ligne/colonne dans les tableaux C et les tableaux Fortran)
ou le système (ASCII, IBM ’ECDCII, ...)
3
Limites des RPC
• Limitations
• paramètres et valeur de retour sont des types primitifs
• programmation procédurale
• dépendance à la localisation du serveur
• pas d’objet
• pas de « référence distante »
• Evolutions
• CORBA
• Multilangage, multi-plateforme (architecture+OS), MuliVendeurs
• Java RMI
• mono-langage : Java, multiplateforme : de JVM à JVM
• DCOM / Object RPC / .NET Remoting
• multi-langages, plateforme Win32 principalement, il existe des implémentations (non MicroSoft) pour Unix,
Propriétaire
• .NET Remoting
• multi-langages (CLR), plateforme Win32 principalement
• Normalisé à l’ECMA et à l’ISO
• SOAP (Simple Access Object Protocol)
• multi-langages, multi-plateforme
• Réponse et requête en XML (DTD SOAP), Transport sur HTTP, IETF
4
Java RMI
Remote Method Invocation
5
Présentation
• RMI est une Application Programming Interface (intégrée au JDK 1.1 et plus à
partir de 1995) ;
6
Présentation
• Mécanisme qui permet l’appel de méthodes entre objets Java qui
s’exécutent éventuellement sur des JVM distinctes ;
• L ’appel peut se faire sur la même machine ou bien sur des machines
connectées sur un réseau ;
8
RMI pour rendre transparents les échanges
9
Java RMI
Architecture
Objet Client Objet Serveur
Proxy Skeleton
Transport
10
Structure des couches RMI
l ’architecture logique
Client RMI Serveur RMI
(Application / Applet / Servlet) HelloServer, rmid
HelloClient,HelloApplet
Invocation de
Interface Distante méthodes Implémentation Distante
Hello sayHello(...) HelloImpl
11
La couche des souches (Amorces)
12
La couche des souches (Amorces)
• Souche ou Stub (sur le client)
– Représentant local de l’objet distant qui implémente les méthodes “exportées” de l’objet
distant.
– “Marshalise” les arguments de la méthode distante et les envoie en un flot de données
au serveur
– “Démarshalise” la valeur ou l ’objet retournés par la méthode distante
– La classe xx_stub peut être chargée dynamiquement par le client (applet)
13
Couche des références distantes Remote
Reference Layer
– Traduit la référence locale au stub en une référence à l’objet distant.
– Elle est servie par un processus tier : rmiregistry, qui est unique par JVM et possède
une table de hachage dont les clés sont des noms et les valeurs sont des objets
distants), il s ’exécute sur chaque machine hébergeant des objets distants ;
– Dans la version 1.1 de JDK, cette couche connecte les clients aux objets distants par
une connexion de type un à un (Unicast). Avant qu’un client ne puisse utiliser les
services d’un objet distant, le service doit être instancié sur le serveur et exporté au
système RMI.
– A partir de JDK 1.2 la gestion des objets activables a été rajoutée à cette couche. 14
La couche transport
- Ecoute les appels entrants;
- Les connexions sont basées sur les adresses IP et les numéros de port. Un nom DNS peut être
utilisé à la place de l’adresse IP.
- En parallèle avec TCP/IP, RMI utilise un protocole propriétaire de bas niveau appelé Java
Remote Method Protocol (JRMP). Deux versions de JRMP existent, la première est associée à la
aversion 1.1 de JDK. Elle oblige l’utilisation d’un Skeleton du côté serveur. La deuxième version
est apparue avec la version 1.2 de JDK et élimine l’utilisation du Skeleton (en utilisant la
réflexion). Le compilateur rmic peut généré les classes de la couche Proxy selon les deux
versions (avec le paramètre –v1.1 ou –v1.2).
15
Structure d’une application RMI
Remote Machine
bind
• Le serveur lie son nom à un objet RMI Server
Registry Registry
• Le client recherche le nom du serveur skeleton
et établie une connexion (lookup).
• Le talon (Stub) sérialise les paramètres return call lookup
au squelette,
• Le squelette invoque la méthode
distante et sérialise le résultat en retour stub
vers le talon.
RMI Client
Local Machine
16
Etapes d’un appel de méthode distante
Client Serveur
Serveur
de noms
3. Interroger
2. Publier
1. Exposer Objet
4. Récupérer distant
Serveur d’objets
7. Appel méthode
6. Arguments
5. Appel de méthode sérialisation
Stub
10. Retour 8. Retour
9. Résultat
17
Création et manipulation d'objets distants
• 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.
18
Création et manipulation d'objets distants
Etapes du développement :
1- Spécifier et écrire l'interface de l'objet distant.
2- Ecrire l'implémentation de cette interface.
3- Ecrire le serveur qui instancie l'objet implémentant
l'interface, exporte son Stub puis attend les requêtes via le
Skeleton.
5- Ecrire le client qui réclame l ’objet distant, importe le
Stub et invoque une méthode de l'objet distant via le
Stub.
19
Classes et interfaces utilisées par Java RMI
20
1- Spécifier l’interface d'un objet distant
• 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 (nom, types de retours, 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, dérivant de la classe java.rmi.Remote.
Exemple:
package examples.hello;
public interface Hello extends java.rmi.Remote{
String sayHello() throws java.rmi.RemoteException;
}
22
2- Implémentation de l’objet distant
• Pour pouvoir être exporté (accepter les requêtes, écouter sur une socket
TCP), un objet doit implémenter l’interface Remote. Il y a alors deux
possibilités pour être exporter:
1. Hériter de la classe java.rmi.server.UnicastRemoteObject. L’appel
au constructeur exportera automatiquement l’objet courant.
2. Appeler la méthode exportObjet() de la classe
UnicastRemoteObject sur l’objet à exporter.
• Lorsqu’un objet est exporté un ensemble de threads est créé pour
attendre les appels de méthodes.
• java.rmi.activation.Activable est utilisée (à la place de
UnicastRemoteObject) pour l’activation d’objets distants.
• Le serveur peut avoir des méthodes locales, absentes de l’interface
distante.
23
2- Implémentation de l ’objet distant
package examples.hello;
public class HelloImpl extends java.rmi.server.UnicastRemoteObject implements Hello {
private String message;
public HelloImpl(String s) throws java.rmi.RemoteException{
super();
message=s; }
public String sayHello() throws java.rmi.RemoteException {
return message ; }
24
2- Implémentation de l ’objet distant
en utilisant UnicastRemoteObject.expotObject
package examples.hello;
public class HelloImpl implements Hello {
private String message;
public HelloImpl(String s) throws java.rmi.RemoteException{
UnicastRemoteObject.expotObject(this);
message=s; }
public String sayHello() throws java.rmi.RemoteException{
return message;
}
25
3- Implémentation du serveur de l’objet distant
• Crée un ou plusieurs objets distants (une ou plusieurs instances)
• Naming.bind() : les enregistre auprès du serveur (registre des noms ) de liaison
rmiregistry, qui gère les associations entre noms symboliques et références d’objets.
• Utilise java.rmi.registry.Registry et la classe Naming.
• Cette classe manipule des noms qui sont des URL de la forme rmi: //hôte :port/nom.
• Où rmi, hôte et port sont optionnels, localhost et 1099 sont par défaut.
Exemple:
rmi://hostname:4242/Odname
rmi://:4242/Odname
//:4242/Odname
/Odname
Odname
26
3- Implémentation du serveur de l’objet distant
• La classe Namming comporte les méthodes suivantes:
1. static void bind (String nom, Remote obj):associe un nom à l’objet obj.
Exp: Naming.bind("Hello1", new HelloImpl("Hello world") );
2. static void rebind (String nom, Remote obj):réassocie un nom à l’objet obj.
3. static void unbind (String nom):désassocie un nom à l’objet obj. Elle permet
de désactiver le serveur.
4. static Remote lookup (String nom):renvoie l’objet Remote associé au nom.
Exp: Naming.lookup("rmi://localhost/Hello1");
5. Static String[] list(): renvoie le tableau des noms présents dans l’annuaire.
27
3- Implémentation du serveur de l’objet distant
Remarques:
• On ne peut utiliser bind ou unbind sur un rmiregistry, que
depuis une VM sur le même host (sécurité).
• On peut utiliser le lookup depuis n’importe quel host.
• L’enregistrement dans l’annuaire est bloquant. Le serveur reste
en attente de requêtes.
• L’utilisation de bind ou rebind implique la création de deux
threads, l’un exécutant le bind (rebind), l’autre continuant
l’exécution de l’application.
• Pour désactiver un serveur, on peut utiliser unbind.
28
3- Implémentation du serveur de l’objet distant
Remarques:
• L ’objet distant servi peut être d’une sous classe de HelloImpl
public class HelloImpl extends HelloImpl {
public HelloImpl() throws java.rmi.RemoteException{ super(Hello); }
}
// et dans HelloServer
java.rmi.Naming.rebind("Hello1", new HelloImpl());
30
4- Implémentation d’un client invoquant l’objet distant
Exemple (Application):
Import java.rmi.*;
package examples.client;
public class HelloClient {
public static void main(String args[]) {
String message = "blank";
try { // récupère le stub de l’objet enregistré au nom de «Hello1»
Hello obj = (Hello) Naming.lookup("rmi://localhost/Hello1");
message = obj.sayHello();
System.out.println(message);
} catch (Exception e) { e.printStackTrace(); }
}}
31
4- Implémentation d ’un client invoquant l ’objet distant
Exemple (Applet)
import java.rmi.Naming;
public class HelloApplet extends java.applet.Applet{
String message = "blank";
public void init() {
try { // récupère le stub de l ’objet enregistré au nom de « HelloObject »
// Remarque : rmiregistry et le serveur Web doit être sur la même machine (même #IP)
Hello obj = (Hello)Naming.lookup("//" + getCodeBase().getHost() + "/HelloObject");
message = obj.sayHello();
} catch (Exception e) { // sortie d ’erreur sur la console
System.out.println("HelloApplet exception:" + e.getMessage()); e.printStackTrace();
}
}
public void paint(java.awt.Graphics g) { g.drawString(message, 25, 50); }
}
32
Déploiement avant compilation
Chez le serveur:
Chez le client:
Hello.java
Hello.java
HelloImpl.java
HelloClient.java
HelloServer.java
• Il faut compiler toutes les classes du coté serveur et client par la commande javac
« nom_de_la_classe».
• Créer les talons client et serveur par la commande rmic HelloImp, celle-ci génère
HelloImp_Stub.class (talon client) et HelloImp_Skel.class (talon serveur).
• A partir de jdk 1.2 le skeleteon n’est plus indispensable.
• A partir de jdk 1.5 le stub n’est plus indisponsable (donc rmic).
33
Déploiement avant compilation
34
L ’exécution Coté Serveur
• Lancer le serveur de noms (le port de liaison par défaut
est le port TCP 1099, doit être >=1024)
• rmiregistry & (sur unix)
• start rmiregistry (sous windows)
35
L ’exécution coté client
• Lancer le client : C:\Client >java HelloClient
Hello Wolrd
C:\Client>
36
L ’exécution Coté Client
• L’applet
• l ’élément HTML applet doit spécifier le codebase
<HTML><title>Hello World</title><center> <h1>Hello World</h1> </center>
The message from the HelloServer is:<br>
<applet codebase="myclasses/"
code="examples.client.HelloApplet" width=500 height=120>
</applet> </HTML>
• seuls les sockets vers hostwww sont autorisés par la sandbox
• donc hostreg = hostser = hostwww
37
Résumé - Java RMI Manuel d'utilisation
38
Résumé - Java RMI - Mode opératoire
• codage
• description de l’interface du service
• écriture du code du serveur qui implante l’interface
• écriture du client qui appelle le serveur
• compilation
• compilation des sources (javac)
• génération des stub et skeleton (rmic)
• activation
• lancement du serveur de noms (rmiregistry)
• lancement du serveur
• lancement du client
39
Aspects avancés des RMI
1- Activation du serveur de noms par le serveur
2- Sécurité
3- Le passage de paramètres
4- Mécanisme du ramasse-miettes distribué
5- RMI et le multithread
6- Callbacks (appels en retour)
7- Fabriques (usines) d’objets
8- Chargement dynamique des classes
9- Activation d’objets
10- Sockets personnalisés et SSL, RMI face aux pare-feux
40
L ’activation du serveur de noms par le serveur
41
L ’activation du serveur de noms par le serveur
import java.rmi.*;
import java.net.*; /*fichier HelloServeur.java*/
public class AddServer2{
public static void main(String[] argv) {
int port;
try {// transformation d ’une chaîne de caractères en entier
Integer I = new Integer(argv[0]);
port = I.intValue();
} catch (Exception ex) { System.out.println(" Donner: Server <port>"); return; }
try { // Création du serveur de nom - rmiregistry
java.rmi.registry.LocateRegistry.createRegistry(port);
InetAddress adrLocale=InetAddress.getLocalHost();
Naming.rebind(‘’//:’’+port+’’/Additionneur’’,new AddImpl());
System.out.println(‘’Serveur attend sur= rmi://’’+adrLocale.getHostAddress()+getHostName()+’’:’’+port+’’/Additionneur’’);
System.out.println(‘’Equivalent à = rmi://’’+InetAddress.getLocalHost().getHostName()+’’:’’+port+’’/Additionneur’’);
} catch (Exception e) {System.out.println(‘’Erreur serveur:’’+e);} } }
42
L ’activation du serveur de noms par le serveur
• Côté serveur:
Lancer le serveur: java HelloServeur
• Côté client:
Lancer le client: java HelloClient
43
Sécurité
• Accepter des connexions réseau de machines distantes ou exécuter
du code téléchargé peut être dangereux.
• Si aucun Security Manager n’est installé, alors, il faut obligatoirement
mettre à la disposition du serveur et du client toutes les classes.
Seules les classes accessibles depuis le CLASSPATH peuvent être
chargées.
• Avec un Security Manager, le serveur et le client peuvent charger
dynamiquement certaines classes.
44
Sécurité
• Une façon de charger un Security Manager s’il n’y en a pas déjà:
if (System.getSecurityManager() == null) {
System.setSecurityManager(new java.rmi.RMISecurityManager()); }
• La spécification des actions autorisées passe par la définition d’un fichier de sécurité:
nomfichier.policy, exemple: java.policy.
45
Sécurité
• Exemple de java.policy:
grant{
permission java.net.SocketPermission « 1024-65535", "connect, accept, resolve";
// This allows RMI clients to make network connections to the public ports on any host
permission java.net.SocketPermission "*:1099", "connect, accept , resolve";
// This allows RMI clients to contact the RMIRegistry of any host
};
grant{
permission java.net.SocketPermission « 1024-65535", "connect, accept";
permission java.net.SocketPermission "*:80", "connect";
// This allows connection to the default web server on any host
//needed for stub downloading, among other things.
};
grant{
permission java.security.AllPermission; //Ceci est dangereux!!
}; 46
Sécurité
Programme du serveur: Exemple Hello World
Import java.rmi.*;
package examples.hello;
public class HelloServer {
public static void main(String args[]) { // argument : l ’hôte/port du rmiregistry
System.setSecurityManager(new RMISecurityManager());
// lance le Security Manager
try {
HelloImpl obj = new HelloImpl("Hello World");
Naming.bind(" Hello1", obj);
System.out.println("Sereveur prêt:");
} catch (Exception e) { e.printStackTrace(); }
}}
47
Sécurité
Programme du Client: Exemple Hello World
Import java.rmi.*;
package examples.client;
public class HelloClient {
public static void main(String args[]) {
System.setSecurityManager(new RMISecurityManager());
// lance le Security Manager
try {
Hello obj = (Hello) Naming.lookup("rmi://localhost/Hello1");
System.out.println(obj.sayHello());
} catch (Exception e) { e.printStackTrace(); }
}}
48
Sécurité: Exécution
Lancer le serveur:
java - Djava.security.policy=java.policy HelloServer
Lancer le client:
java - Djava.security.policy=java.policy HelloClient
Le fichier java.policy doit se trouver dans le répertoire courant du serveur et du client (il
n’y a pas eu de chargement dynamique de code).
49
Sécurité: Exécution
On peut ne pas placer un SecurityManager au niveau du server et le
prévoir au moment du lancement du rmiregistry:
rmirestry - j- Djava.security.policy=java.policy
50
Le passage de paramètres
51
Le passage de paramètres
52
Le passage de paramètres
• L’argument ou la valeur de retour d’une méthode distante peut être de
n’importe quel type Java: type simple, objet local ou objet distant.
• Pour les paramètres locaux (objets ou type primitifs), le transfert se fait
nécessairement par copie.
• S’il s’agit d’un objet (X), l’ensemble de ses variables est copié par
sérialisation, il doit donc implémenter java.io.Serializable. La déclaration
de la classe X est:
Public class X implements java.io.Serializable{…..}
La classe X doit se trouver chez le client et chez le serveur.
53
Le passage de paramètres
Exemple : Paramètre de type objet local
public interface AddInterface extends Remote public classe Matrice implements Serializable
{public Matrice add(Matrice a, Matrice b) { public int m[][] =new int [][];
Throws RemoteException;} public void remplirmatrice()
{…}
55
Le passage de paramètres
Exemple: Paramètre de type objet distant
Fichier I1.java
import java.rmi.*
public interface I1 extends Remote {
Public l2 getI2() throws RemoteException;
}
Fichier I2.java
import java.rmi.*
public interface I2 extends Remote { }
56
Le passage de paramètres
Exemple: Paramètre de type objet distant
Fichier Client.java
import java.rmi.*
public class client{
public static void main(String args[]){
try{
I1 obj= (I1) Naming.lookup(’’rmi://1050’’+ args[0]+’’/Hello’’);
I2 msg= obj.getI2();
}catch (Exception e)
{System.out.println(’’Client exception’’+e);}}}
57
Résumons
• Toute variable primitive est passé par copie.
• Tout objet est passé par copie.
• Mais comment copier un objet?
• Il ne faut pas copier que l’objet.
• Il faut aussi copier toutes ses références.
• Très fastidieux à faire à la main.
• Heureusement, une API le fait pour nous: la Serialization.
Serialization
62
La Désérialisation
Deserialization
63
Gestion des cycles
• La sérialisation est un processus récursif
• Que se passe-t-il quand il y a un cycle dans les graphe d’objets?
3
1 Serialization
2 4
1 2 3 4 Ref2
65
Utiliser la sérialisation
• Par défaut, un objet n’est pas sérialisable
– Problème de securité: la sérialisation ignore les droits d’accés (private…)
– Levée d’une NotSerializableException
• Il faut donc explicitement indiquer qu’un objet est sérialisable
• Marquage au niveau de la classe
– Toutes les instances seront sérialisable
– Les sous classes d’une classe sérialisable sont sérialisable
• Utilisation de l’interface java.io.Serializable
– Interface marqueur, aucune méthode à implémenter
66
Utiliser la sérialisation
• RMI fait appel à la sérialisation
– Totalement transparent
• Mais on peut aussi l’utiliser manuellement
– Très pratique pour copier des objets
• Étapes
– Bien vérifier que les objets sont sérialisables
– Créer des flux d’entrée et de sortie (input et output streams)
– Utiliser ces flux pour créer des flux objets (object input et object output streams)
– Passer l’objet à copier à l’object output stream
– Le lire depuis l’object input stream
67
Contrôler la sérialisation
69
Contrôler la sérialisation
70
Contrôler la sérialisation
71
Écriture - Lecture
72
Exemple: comportement par défaut
public class Defaut implements Serializable {
public Defaut() { }
73
Exemple: sauvegarde d’un entier
74
Sérialisation et héritage
• Les sous classes d’une classe sérialisable sont sérialisables
• Mais une classe peut-être sérialisable, alors que son parent ne
l’est pas
– La sous-classe est responsable de la sauvegarde/restauration des
champs hérités
– Lors de la désérialisation, les constructeurs sans paramètres seront
appelés pour initialiser les champs non sérialisables
– Le constructeur vide de la classe parent sera appelé
• Source de bugs très difficiles à identifier
75
Mécanisme du ramasse-miettes:
Cas d’un objet local
• Un objet local est considéré vivant si au moins une variable le
référence.
public objet()
{nbreObjets++;
System.out.println(‘’je suis l’objet’’+nbreObjets);} Une exécution possible:
Je suis l’objet 1
Protected void finalize() {nbreObjets--;} Je suis l’objet 2
} Je suis l’objet 3
Je suis l’objet 3
Je suis l’objet 3
Public classe TestObjet
{ public static void main (String[]args)
{Objet o;
For (int i=0; i<5;i++)
{o=new Objet();//l’objet précédemment référencé par o devient candidat au ramasse-miettes
System.gc();} //force le Ramasse-miettes à libérer la mémoire 77
}}
Mécanisme du ramasse-miettes:
Cas d’un objet distant
Le DGC interagit avec le GC locaux et utilise deux mécanismes reference-
counting et lease periode:
Concernant le reference-counting:
-Djava.rmi.dgc.leaseValue=1000 (bail=1sc)
java -Djava.rmi.dgc.leaseValue=1000 HelloServer 79
Mécanisme du ramasse-miettes:
Cas d’un objet distant
• Si la valeur du bail est très petite, le serveur lui-même peut se
terminer avant que le client n’est eu le temps de le référencer.
81
Exécution Hello World
Chez le serveur:
java –Djava.rmi.dgc.leaseValue= 1000
HelloServer
Serveur Prêt:
Fin d’un objet distant
Fin d’un objet local
C:\Serveur>
Remarques: après 1000 ms, le client n’a toujours pas été lancé.
La présence des stubs est nécessaire et donc rmic HelloImpl (même avec java 1.5)
82
Mécanisme du ramasse-miettes distribué
Exemple pour un objet distant
import java.rmi.*;
public interface Hello extends Remote{
public Msg getMsg() throws Remote Exception;
}
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
public class HelloImpl extends UnicastRemoteObject implements Hello {
public HelloImpl() throws RemoteException{
super();
}
public Msg getMsg() throws RemoteException {return (Msg)new MsgImp();}
83
}
Mécanisme du ramasse-miettes distribué
Exemple pour un objet distant
import java.rmi.Remote;
public interface Msg extends Remote{ }
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.Unreferenced;
public class MsgImpl extends UnicastRemoteObject implements Msg, Unreferenced {
public static int couner;
private int id;
public MsgImpl() throws RemoteException{
super();
this.id=++MsgImpl.counter;
System.out.println(’’ Message created:’’+MsgImpl.counter);
}
Public void unreferenced() {
System.out.println(’’ Methode unreferenced() called by’’+this.id); 84
}}
Mécanisme du ramasse-miettes distribué
Exemple pour un objet distant
import java.rmi.Naming;
public class Server{
public static void main(String args[ ]) {
String host=‘’ ‘’;
try {
if (args.length==0) {host=‘’localhost’’;} else {host=args[0];}
Hello obj=new HelloImpl();
System.out.println (‘’HelloImpl instanciated.’’);
Naming.rebind(‘’rmi://’’ +host+ ‘’/Hello’’,obj);
System.out.println (‘’HelloImpl registred.’’);
}catch (Exception e){
System.out.println(e);
}}} 85
Mécanisme du ramasse-miettes distribué
Exemple pour un objet distant
import java.rmi.Naming;
import java.rmi.server.UnicastRemoteObject;
public class Client{
public static void main(String args[ ]) {
String host=‘’ ‘’;
try {
if (args.length==0) {host=‘’localhost’’;} else {host=args[0];}
Hello obj=(Hello) Naming.lookup(‘’rmi://’’ +host+ ‘’/Hello’’);
for(int i=0;i<3;i++){
Msg msg=obj.getMsg();
}
}catch (Exception e){
System.out.println(‘’Client exception: ’’+e); 86
}}}
Mécanisme du ramasse-miettes distribué
Exemple pour un objet distant
java –Djava.rmi.dgc.leaseValue= 100 Server
HelloImpl instanciated.
HelloImpl registered.
Message created:1
Message created:2
Methode unreferenced() called by 2
Methode unreferenced() called by 1
Message created:3
Methode unreferenced() called by 3
C:\Serveur>
Remarques: La présence des stubs HelloImpl_stub est nécessaire et donc rmic HelloImpl (même avec java 1.5).
Pour avoir ces affichages, le client doit être lancé dans les 100 ms.
87
Mécanisme du ramasse-miettes distribué
Exemple pour un objet distant
HelloImpl instanciated.
HelloImpl registered.
C:\Serveur>
88
RMI et le Multithread
89
RMI et les threads
90
Quelques mots sur les Threads
Un thread permet l’exécution d’un programme.
Une application peut avoir de multiples threads qui s ’exécutent concurremment
(chaque thread a une priorité).
Chaque thread a un nom. Plusieurs threads peuvent avoir le même. Le nom est
généré si non spécifié.
Il y a 2 façons de créer un nouveau thread d’exécution.
• Déclarer une sous classe de thread et surcharger la méthode run. Une
instance de la sous classe peut alors être allouée et démarrer.
• Déclarer une classe qui implémente runnable et donc la méthode run. Une
instance de la classe peut être allouée, passée comme argument à la création
d’un thread et démarrée.
RMI et le Multithread
Exemple du Producteur / Consommateur
/*Fichier BufferInterface.java*/
92
RMI et le Multithread
Exemple du Producteur / Consommateur
/*Fichier BufferInterface.java*/
public class BufferInterfaceImpl extends java.rmi.server.UnicastRemoteObject
implements BufferInterface {
Object buffer[];
int taille;
int ecrire;
int lire;
int nombre;
BufferInterfaceImpl(int n) throws RemoteException{
buffer =new Object[n];
taille=n; ecrire=0; lire=0; nombre=0;
} 93
RMI et le Multithread
Exemple du Producteur / Consommateur
94
RMI et le Multithread
Exemple du Producteur / Consommateur
/*Fichier BufferInterfaceImpl.java*/
}}
RMI et le Multithread
Exemple du Producteur / Consommateur
/*Fichier Producteur.java*/
import java.util.*;
100
Déploiement Producteur / Consommateur
Chez le serveur:
• BufferInterface
• BufferInterfaceImpl
• ServeurBuffer
Chez le client:
• BufferInterface
• Client
• Consommateur
• Producteur
101
Exécution du Producteur /
Consommateur chez le serveur
C:\RMIExemples\start rmiregistry
C:\RMIExemples\ProdCons\Serveur>java ServeurBuffer
102
Exécution du Producteur /
Consommateur chez le client
C:\RMIExemples\ProdCons\Client>java Client ServeurBuffer localhost
103
Deadlock distribué
• Il faut indiquer à la JVM que cet objet est bien un objet RMI, sinon il sera
sérialisé! D’où l’utilisation des méthodes statiques exportObject et
unexportObjet de UnicastRemoteObject.
• Un Callback peut être utilisé pour des retours d’information, pour des
applications de chat où les clients sont des objets distants.
105
Définition de l’interface
Exemple Hello World en utilisant un Callback
/*Fichier HelloInterface.java*/
import java.rmi.*;
public interface HelloInterface extends Remote{
/*Méthode imprimant un message prédéfini dans l’objet appelé */
public String sayHello(lclient oclient) throws RemoteException;
}
106
Implémentation de l’interface
Exemple Hello World en utilisant un Callback
/*Fichier HelloImpl.java*/
import java.rmi.*;
import java.rmi.server.*;
public class HelloImpl extends UnicastRemoteObject implements
HelloInterface {
private String message;
public HelloImpl(String s) throws RemoteException{
message=s; }
public String sayHello(lclient oclient) throws RemoteException {
return message+« »+oclient.getName() ; } 107
Définition de l’interface lclient
Exemple Hello World en utilisant un Callback
/*Fichier lclient.java*/
import java.rmi.*;
public interface lclient extends Remote{
public String getName( ) throws RemoteException;
}
108
Implémentation de l’interface lclient
Exemple Hello World en utilisant un Callback
/*fichier lclientImpl.java*/
import java.rmi.*;
public class lclientImpl implements lclient{
private String name;
public lclientImpl(String name) throws RemoteException{
this.name=name; }
public String getName( ) throws RemoteException {
return this.name;} }
109
Programme du serveur
Exemple Hello World en utilisant un Callback
/* fichier HelloServer.java*/
Import java.rmi.*;
public class HelloServer {
public static void main(String args[]) {
try {
Naming.rebind(" Hello1", new HelloImpl("Hello World"));
System.out.println("Sereveur prêt:");
} catch (Exception e) { e.printStackTrace(); }
}}
110
Programme du client
Exemple Hello World en utilisant un Callback
/*Fichier HelloClient.java*/
import java.rmi.*;
import java.rmi.server.*;
Chez le client:
• HelloInterface
• HelloClient
• lclient
• lclientImpl
• lclientImpl_Stub
Chez le serveur:
• HelloInterface
• HelloImpl
• HelloServer
• lclien
• lclientImpl_Stub
112
Hello World en utilisant un Callback
Exécution
C:\RMIExemples\Callback\Server>start rmiregistry
C:\RMIExemples\Callback\Server>java HelloServer
Serveur prêt:
113
Fabrique d’objets (Usines d’objets, classes Factory)
• Pour rendre un objet distant visible pour les clients à travers rmirestry, l’objet
doit être créer explicitement à l’intérieur d’une machine virtuelle java sur le
serveur, puis enregistrer en utilisant le bind() ou rebind() sur le registre.
RMI Restry
ObjectFactoryC
réf new()
Client
Objets de
la classe C
115
Fabrique d’objets (Usines d’objets, classes Factory)
116
Fabrique d’objets - Exemples
117
Fabrique d’objets
Exemples: Annuaire
public interface Annuaire extends Remote{
public String titre;
public boolean inserer(String nom, Info info) throws RemoteException, ExisteDeja;
public boolean supprimer(String nom)throws RemoteException, PasTrouve;
public Info rechercher(String nom) throws RemoteException, PasTrouve;
}
import java.rmi.*
public interface FabAnnuaire extends Remote{
public Annuaire newAnnuaire(String titre) throws RemoteException ;
}
119
Fabrique d’objets
Implémentation de la fabrique
public FabAnnuaireImpl{};
120
Fabrique d’objets
Mise en œuvre de la fabrique
Le serveur
import java.rmi.*;
public class Server {
public static void main (String [ ] argv)
{
/* lancer SecurityManager */
System.setSecurityManager (new RMISecurityManager ()) ;
try {
Naming.rebind ("Fabrique”,new (FabAnnuaireImpl)) ;
System.out.println ("Serveur prêt.") ;
} catch (
Exception e) {
System.out.println
("Erreur serveur : " + e) ;
}}}
121
Fabrique d’objets
Utilisation de la fabrique
Programme client
import java.rmi.*;
public class Client {
public static void main (String [ ] argv) {
/* lancer SecurityManager */
System.setSecurityManager (new RMISecurityManager ()) ;
try {/* trouver une référence vers la fabrique */
FabAnnuaire fabrique =(FabAnnuaire ) Naming.lookup("rmi://goedel.imag.fr/Fabrique") ;
/* créer un annuaire */
annuaireIMAG = fabrique.newAnnuaire("IMAG");
/* créer un autre annuaire */
annuaireINRIA= fabrique.newAnnuaire("INRIA");
/* utiliser les annuaires */
annuaireIMAG.inserer(..., ...);
annuaireINRIA.inserer(..., ...);
....
} catch (Exception e) {System.out.println("Erreur client : " + e) ;
}}}
122
Fonctionnement d’ensemble de la fabrique
123
Chargement dynamique de classes
• Un client a besoin d’une souche dont la classe n’est pas dans CLASSPATH,
chargement dynamique du Stub.
Exemple de polymorphisme:
• Dans le cas où le protocole http est utilisé, les classes doivent être chargées dans
un serveur Web.
Une fois que toutes les définitions de classe sont disponibles, la méthode
proxy du stub appelle les objets sur le serveur.
128
Les différentes étapes d’un chargement dynamique
2. Les compiler.
129
Les différentes étapes d’un chargement dynamique
130
Exemple Hello Wolrd
Fichiers nécessaires si chargement dynamique
131
Exemple Hello World avec chargement dynamique:
Le serveur dynamique
Le serveur dynamique :
import java.rmi.Naming;
import java.rmi.Remote;
import java.rmi.RMISecurityManager;
import java.rmi.server.RMIClassLoader;
import java.util.Properties;
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, "Reverse");
Naming.rebind("rmi://sinus.cnam.fr:1099/MyReverse",(Remote) ClasseServeur.newInstance());
System.out.println("Objet Reverse lié dans le RMIregistry");
System.out.println("Attente des invocations des clients ...");}
catch (Exception e) {System.out.println("Erreur de liaison de l'objet Reverse");
System.out.println(e.toString());}}}
132
Exemple Hello World avec chargement dynamique:
Le client dynamique
Le client dynamique :
import java.rmi.RMISecurityManager;
import java.rmi.server.RMIClassLoader;
import java.util.Properties;
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
134
Activation d’objets
Problématique
• Le nombre d’objets distribués par JVM est limité
• Dans des conditions réelles d’utilisation, plusieurs milliers d’objets peuvent être distribués
simultanément
• À un instant donné, seule une partie des objets distribués est utilisée
lancer des JVM (proposant des objets distribués) à la demande
C’est le rôle des objets activables
Outil/Package
Un package java.rmi.activation
Un démon rmid qui active les objets à la demande
135
Activation d’objets
• Permet de n’activer des objets que quand ils sont utilisés.
• L’activation peut être repoussée jusqu’à la première utilisation par le client, donc
première invocation de méthode.
• Rend les objets persistants (Enregistrés dans le système de fichier lorsqu’ils sont
désactivés).
• Un démon rmid s’occupe d’activer les objets quand ils reçoivent des requêtes.
137
Activation d’objets: cycle de développement
1. Créer l’interface
2. Créer une implémentation de l’objet, qui:
Étend Activable et non java.rmi.server.UnicastRemoteObject et possède le
constructeur obligatoire XX(ActivationID id, MarshalledObject data)
3. Créer le serveur, qui:
Crée les groupes d’activation
Crée les objets et les associe au groupe d’activation
Enregistre l’objet auprès du registre
4. Créer un client « standard »
5. Lancer le registre :rmirestry
6. Lancer le système d’activation :rmid
7.Lancer le serveur.
8.Lancer le client.
138
Etapes principales du serveur
140
Exemple: HelloServer.java
avec activation d’objets
import java.rmi.registry.LocateRegistry ;
import java.rmi.registry.Registry ;
import java.rmi.RMISecurityManager ;
import java.rmi.activation .*;
import java.util.Properties ;
import java.util.Arrays ;
141
Exemple: HelloServer.java
public class Server {
avec activation d’objets
public static void main ( String args []) throws Exception {
int port = 1099;
if ( args . length ==1)
port = Integer.parseInt ( args [0]) ;
try { System.setSecurityManager (new RMISecurityManager ());
Properties props = new Properties ();
ActivationGroupDesc my_group_desc = new ActivationGroupDesc (props , null);
ActivationGroupID my_group_id = ActivationGroup . getSystem (). registerGroup (my_group_desc );
ActivationGroup.createGroup ( my_group_id , my_group_desc , 0);
ActivationDesc objectdesc = new ActivationDesc ( my_group_id , " HelloImpl ", "", null );
Hello stub = (Hello) Activatable.register ( objectdesc );
Registry registry = LocateRegistry . getRegistry ( port );
if (! Arrays.asList ( registry . list ()). contains (" HelloActivatable "))
registry.bind (" HelloActivatable ", stub );
Else registry . rebind (" HelloActivatable ", stub );
System.out.println (" HelloActivatable active et lie au registre "); }
catch ( Exception e){ System . out. println (" Exception "+ e);}}}
142
Exemple: Client.java
avec activation d’objets
import java.rmi.registry.LocateRegistry ;
import java.rmi.registry.Registry ;
public class Client {
public static void main ( String args []) {
String machine = " localhost ";
int port = 1099;
if ( args.length ==3) {
machine = args [0];
port = Integer . parseInt ( args [1]) ;
} else if ( args.length ==2)
machine = args [0];
try {
Registry registry = LocateRegistry . getRegistry ( machine , port );
Hello stub = ( Hello ) registry . lookup (" HelloActivatable ");
System .out. println ( stub . sayHello ( args [ args . length -1]) );
} catch ( Exception e) {
System .out. println (" Client exception : " +e);
}}} 143
Exemple: helloworld.policy
avec activation d’objets
grant {
// permission java.net.SocketPermission "*:1024 -65535" ," listen , connect
,accept , resolve";
// permission java.net.SocketPermission "*:80" , " connect ";
permission java.security . AllPermission ; /* on autorise tout */
};
144
Exemple: l’exécution
avec activation d’objets
• Lancement de rmiregistry
• Lancement de rmid:
rmid -J- Djava.security.policy=java.policy
• Lancement du client:
java Client 145
Autres aspects avancés de RMI
146