Vous êtes sur la page 1sur 14

Ecole Nationale des Sciences Appliquées

EL JADIDA

Volume 1

Programmation Réseau et Distribuées


JAVAEE

Dr. Mohamed LACHGAR


lachgar.m@gmail.com

2019 - 2020
2
Contents

1 RMI : Remote Method Invocation 5


1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 La présentation et l’architecture de RMI . . . . . . . . . . . . . . . . . . . . 5
1.3 Appel local versus Appel à distance . . . . . . . . . . . . . . . . . . . . . . . 6
1.4 Les étapes pour créer un OD et l’appeler avec RMI . . . . . . . . . . . . . 7
1.4.1 Le développement coté serveur . . . . . . . . . . . . . . . . . . . . . 8
1.4.2 Le développement coté client . . . . . . . . . . . . . . . . . . . . . . 12
1.5 TP 1 : RMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

3
4 CONTENTS
Chapter 1

RMI : Remote Method Invocation

1.1 Introduction
RMI (Remote Method Invocation) est une technologie développée et fournie par Sun à
partir du JDK 1.1 pour permettre de mettre en œuvre facilement des objets distribués.

RMI permet la communication entre machines virtuelles Java (JVM) qui peuvent se
trouver physiquement sur la même machine ou sur deux machines distinctes.

1.2 La présentation et l’architecture de RMI


Le but de RMI est de permettre l’appel, l’exécution et le renvoi du résultat d’une méth-
ode exécutée dans une machine virtuelle différente de celle de l’objet l’appelant. Cette
machine virtuelle peut être sur une machine différente pourvu qu’elle soit accessible par
le réseau.

La machine sur laquelle s’exécute la méthode distante est appelée serveur.

L’appel coté client d’une telle méthode est un peu plus compliqué que l’appel d’une
méthode d’un objet local mais il reste simple. Il consiste à obtenir une référence sur
l’objet distant puis à simplement appeler la méthode à partir de cette référence.

La technologie RMI se charge de rendre transparente la localisation de l’objet distant,


son appel et le renvoi du résultat.

En fait, elle utilise deux classes particulières, le stub et le skeleton, qui doivent être
générées avec l’outil rmic fourni avec le JDK.

Le stub est une classe qui se situe côté client et le skeleton est son homologue coté
serveur. Ces deux classes se chargent d’assurer tous les mécanismes d’appel, de commu-
nication, d’exécution, de renvoi et de réception du résultat.

5
6 CHAPTER 1. RMI : REMOTE METHOD INVOCATION

Figure 1.1: Architecture RMI

1.3 Appel local versus Appel à distance

Figure 1.2: Appel local vs Appel à distance

Les amorces (Stub/Skeleton)

• Elles assurent le rôle d’adaptateurs pour le transport des appels distants

• Elles réalisent les appels sur la couche réseau

• Elles réalisent l’assemblage et le désassemblage des paramètres

• Une référence d’objets distribué correspond à une référence d’amorce

• Les amorces sont créées par le générateur rmic.


1.4. LES ÉTAPES POUR CRÉER UN OD ET L’APPELER AVEC RMI 7

Les Stubs
• Représentants locaux de l’objet distribué ;

• Initient une connexion avec la JVM distante en transmettant l’invocation distante


à la couche des références d’objets ;

• Assemblent les paramètres pour leur transfert à la JVM distante ;

• Attendent les résultats de l’invocation distante ;

• Désassemblent la valeur ou l’exception renvoyée ;

• Renvoient la valeur à l’appelant ; S’appuient sur la sérialisation.

Les squelettes
• Désassemblent les paramètres pour la méthode distante ;

• Font appel à la méthode demandée ;

• Assemblage du résultat (valeur renvoyée ou exception) à destination de l’appelant.

Etapes d’un appel de méthode distante

Figure 1.3: Etapes d’un appel de méthode distante

1.4 Les étapes pour créer un OD et l’appeler avec


RMI
Le développement coté serveur se compose de :
• La définition d’une interface qui contient les méthodes qui peuvent être appelées à
distance;
8 CHAPTER 1. RMI : REMOTE METHOD INVOCATION

• L’écriture d’une classe qui implémente cette interface;

• L’écriture d’une classe qui instanciera l’objet et l’enregistrera en lui affectant un


nom dans le registre de nom RMI (RMI Registry).

Le développement côté client se compose de :


• L’obtention d’une référence sur l’objet distant à partir de son nom;

• L’appel à la méthode à partir de cette référence.

Enfin, il faut générer les classes stub et skeleton en exécutant le programme rmic avec le
fichier source de l’objet distant.

1.4.1 Le développement coté serveur


Côté serveur, l’objet distant est décrit par une interface. Une instance de l’objet doit être
créé et enregistrée dans le registre RMI.

La définition d’une interface qui contient les méthodes de l’objet distant


L’interface à définir doit hériter de l’interface java.rmi.Remote. Cette interface ne contient
aucune méthode mais indique simplement que l’interface peut être appelée à distance.

L’interface doit contenir toutes les méthodes qui seront susceptibles d’être appelées à
distance.

La communication entre le client et le serveur lors de l’invocation de la méthode dis-


tante peut échouer pour diverses raisons telles qu’un crash du serveur, une rupture de la
liaison, etc ...

Ainsi chaque méthode appelée à distance doit déclarer qu’elle est en mesure de lever
l’exception java.rmi.RemoteException.

Exemple :

import java.rmi.Remote;
import java.rmi.RemoteException;
public interface FactImpl extends Remote {
public double Fact(double n) throws RemoteException;
}

L’écriture d’une classe qui implémente cette interface


Cette classe correspond à l’objet distant.

Elle doit donc implémenter l’interface définie et contenir le code nécessaire. Cette classe
doit obligatoirement hériter de la classe UnicastRemoteObject qui contient les différents
1.4. LES ÉTAPES POUR CRÉER UN OD ET L’APPELER AVEC RMI 9

traitements élémentaires pour un objet distant dont l’appel par le stub du client est
unique. Le stub ne peut obtenir qu’une seule référence sur un objet distant héritant de
la classe UnicastRemoteObject. On peut supposer qu’une future version de RMI sera ca-
pable de faire du MultiCast, permettant à RMI de choisir parmi plusieurs objets distants
identiques la référence à fournir au client.

La hiérarchie de la classe UnicastRemoteObject est : Comme indiqué dans l’interface,

Figure 1.4: Hiérarchie de la classe UnicastRemoteObject

toutes les méthodes distantes, mais aussi le constructeur de la classe, doivent indiquer
qu’elles peuvent lever l’exception RemoteException. Ainsi, même si le constructeur ne
contient pas de code il doit être redéfini pour inhiber la génération du constructeur par
défaut qui ne lève pas cette exception.

Exemple :

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

public class Facto extends UnicastRemoteObject implements FactImpl{


public Facto() throws RemoteException {
}
public double Fact(double n) throws RemoteException {
if (n==0 || n == 1) return 1;
return n * Fact( n - 1);
}
}

L’écriture d’une classe pour instancier l’objet et l’enregistrer dans le registre


Ces opérations peuvent être effectuées dans la méthode main d’une classe dédiée ou dans
la méthode main de la classe de l’objet distant. L’intérêt d’une classe dédiée et qu’elle
permet de regrouper toutes ces opérations pour un ensemble d’objets distants.

La marche à suivre contient trois étapes :

• la mise en place d’un security manager dédié qui est facultative;

• l’instanciation d’un objet de la classe distante;


10 CHAPTER 1. RMI : REMOTE METHOD INVOCATION

• l’enregistrement de la classe dans le registre de noms RMI en lui donnant un nom.

1. La mise en place d’un security manager


Cette opération n’est pas obligatoire mais elle est recommandée en particulier si le
serveur doit charger des classes récupérées sur des machines distantes. Sans security
manager, il faut obligatoirement mettre à la disposition du serveur toutes les classes
dont il aura besoin (Elles doivent être dans le CLASSPATH du serveur). Avec un
security manager, le serveur peut charger dynamiquement certaines classes.
Cependant, le chargement dynamique de ces classes peut poser des problèmes de
sécurité car le serveur va exécuter du code d’une autre machine. Cet aspect peut
conduire à ne pas utiliser de security manager.
public static void main(String[] args) {
try {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
} catch (Exception e) {
e.printStrackTrace();
}
}

Il est aussi possible d’activer un security manager en utilisant simplement l’option


-Djava.security.manager de la JVM.

2. L’instanciation d’un objet de la classe distante


Cette opération est très simple puisqu’elle consiste simplement en la création d’un
objet de la classe de l’objet distant
public static void main (String er[]){
try {
if(System.getSecurityManager() == null) {
System.setSecurityManager(newRMISecurityManager());
}
Facto f = new Facto();
} catch (Exception ex) {
Logger.getLogger(Serveur.class.getName()).log(Level.SEVERE,
null, ex);
}
}

3. L’enregistrement dans le registre de noms RMI


La dernière opération consiste à enregistrer l’objet créé dans le registre de noms
en lui affectant un nom. Ce nom est fourni au registre sous forme d’une URL
constituée du préfix rmi://, du nom du serveur (hostname) et du nom associé à
l’objet précédé d’un slash.
Le nom du serveur peut être fourni « en dur » sous forme d’une constante chaîne
de caractères ou peut être dynamiquement obtenu en utilisant la classe InetAddress
pour une utilisation en locale.
C’est ce nom qui sera utilisé dans une URL par le client pour obtenir une référence
1.4. LES ÉTAPES POUR CRÉER UN OD ET L’APPELER AVEC RMI 11

sur l’objet distant.


L’enregistrement se fait en utilisant la méthode rebind de la classe Naming. Elle
attend en paramètre l’URL du nom de l’objet et l’objet lui-même.
public static void main(String er[]) {
try {
Facto f = new Facto();
String url = "rmi://" +
InetAddress.getLocalHost().getHostAddress() + "/FactRMI";
System.out.println("Enregistrement de l'objet avec l'url : " +
url);
Naming.rebind("rmi://localhost/fact", f);
System.out.print("serveur lancé....");
} catch (Exception ex) {
Logger.getLogger(Serveur.class.getName()).log(Level.SEVERE,
null, ex);
}
}

4. Le lancement dynamique du registre de noms RMI


Sur le serveur, le registre de noms RMI doit s’exécuter avant de pouvoir enregistrer
un objet ou obtenir une référence.
Ce registre peut être lancé en tant qu’application fournie dans le JDK (rmireg-
istry) comme indiqué dans un chapitre suivant ou être lancé dynamiquement dans
la classe qui enregistre l’objet. Ce lancement ne doit avoir lieu qu’une seule et
unique fois. Il peut être intéressant d’utiliser le code ci-dessous si l’on crée une
classe dédiée à l’enregistrement des objets distants.
Le code pour exécuter le registre est la méthode createRegistry() de la classe
java.rmi.registry.LocateRegistry. Cette méthode attend en paramètre un numéro
de port.
public static void main(String er[]) {
try {
Facto f = new Facto();
String url = "rmi://" +
InetAddress.getLocalHost().getHostAddress() + "/FactRMI";
System.out.println("Enregistrement de l'objet avec l'url : " +
url);
LocateRegistry.createRegistry(1099);
Naming.rebind("rmi://localhost/fact", f);
System.out.print("serveur lancé....");
} catch (Exception ex) {
Logger.getLogger(Serveur.class.getName()).log(Level.SEVERE,
null, ex);
}
}

Résultat :
12 CHAPTER 1. RMI : REMOTE METHOD INVOCATION

Figure 1.5: Résultat

1.4.2 Le développement coté client


L’appel d’une méthode distante peut se faire dans une application ou dans une applet.

1. La mise en place d’un security manager


Comme pour le coté serveur, cette opération est facultative.
Le choix de la mise en place d’un sécurity manager côté client suit des règles iden-
tiques à celles appliquées côté serveur. Sans son utilisation, il est nécessaire de
mettre dans le CLASSPATH du client toutes les classes nécessaires dont la classe
stub.
public static void main(String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
}

2. L’obtention d’une référence sur l’objet distant à partir de son nom


Pour obtenir une référence sur l’objet distant à partir de son nom, il faut utiliser
la méthode statique lookup() de la classe Naming.
Cette méthode attend en paramètre une URL indiquant le nom qui référence l’objet
distant. Cette URL est composée de plusieurs éléments : le préfix rmi://, le nom
du serveur (hostname) et le nom de l’objet tel qu’il a été enregistré dans le registre
précédé d’un slash.
Il est préférable de prévoir le nom du serveur sous forme de paramètres de l’application
ou de l’applet pour plus de souplesse.
La méthode lookup() va rechercher l’objet dans le registre du serveur et retourner
un objet stub. L’objet retourné est de la classe Remote (cette classe est la classe
mère de tous les objets distants).
Si le nom fourni dans l’URL n’est pas référencé dans le registre, la méthode lève
l’exception NotBoundException.
public static void main(String r[]) {
try {
Remote f = Naming.lookup("rmi://localhost/fact");
} catch (NotBoundException ex) {

} catch (MalformedURLException ex) {

} catch (RemoteException ex) {

}
}
1.5. TP 1 : RMI 13

3. L’appel de la méthode à partir de la référence sur l’objet distant


L’objet retourné étant de type Remote, il faut réaliser un cast vers l’interface qui
définit les méthodes de l’objet distant. Pour plus de sécurité, on vérifie que l’objet
retourné est bien une instance de cette interface.
Un fois le cast réalisé, il suffit simplement d’appeler la méthode.
public static void main(String r[]) {
try {
Remote f = Naming.lookup("rmi://localhost/fact");
System.out.print(((FactImpl)f).Fact(4));
} catch (NotBoundException ex) {
ex.printStackTrace();
} catch (MalformedURLException ex) {
ex.printStackTrace();
} catch (RemoteException ex) {
ex.printStackTrace();
}
}

1.5 TP 1 : RMI
Exercice 1 :
On souhaite réaliser un serveur RMI qui offre les quatre services suivants :

• Trie d’une liste d’entiers,

• Calcule de factoriel,

• Inverse d’une chaine de caractère,

• Calcule l’occurrence d’un caractère dans une chaine de caractère.

Figure 1.6: Architecture


14 CHAPTER 1. RMI : REMOTE METHOD INVOCATION

1. Créer les interfaces nécessaires pour publier les quatre services.

2. Créer une classe qui implémente les interfaces développées dans la question 1.

3. Créer une classe Server qui publie les quatre objets distribués.

4. Créer un client qui consomme les quatre services.

Exercice 2 :
Nous disposons de deux services implantés sous forme d’objets ObjetString et ObjetCal-
cul : un qui réalise des opérations sur les chaînes de caractère, l’autre qui réalise du calcul
numérique. Pour simplifier, l’objet ObjetString offre une seule méthode nbOccurrences
qui calcule le nombre d’occurrences d’un caractère dans une chaîne de caractères (un
mot) et l’objet ObjetCalcul offre une seule méthode add qui calcule la somme de deux
nombres. Voici le code de chacune de ces méthodes.
public int add (int a, int b) {
return a+b;
}

public int nbOccurrences(String c, String chaineOrigine) {


int longueur = chaineOrigine.length();
int nb = 0;
for (int i = 0; i < longueur; i++)
if ((chaineOrigine.substring(i, i+1)).equals(c))
nb++;
return nb;
}

1. On souhaite rendre chacune de ces méthodes accessibles à distance. Donnez alors


la structure des interfaces qui seront partagées par le serveur et le client sachant
que chaque méthode appartient à un objet distinct.

2. Compléter le code de ces méthodes afin qu’elles puissent gérer les erreurs dues à
leur appel à distance.

3. Sachant que toute méthode Java appelée par un programme Java distant doit ap-
partenir à un objet accessible à distance. Donnez la structure des classes Java qui
vont représenter respectivement l’objet ObjetString et l’objet ObjetCalcul.

4. Si les objets ObjetString et ObjetCalcul doivent être installés sur la machine 198.168.21.11,
quelles sont les autres classes Java à implanter sur la machine 198.168.21.11. Don-
nez leur structure générale.

5. Donnez les commandes à lancer sur la machine 198.168.21.11 afin que les méthodes
add et nbOccurrences puissent être appelées par des clients distants si le service de
noms est activé sur le port 2012.

6. Ecrire le programme du client qui doit être lancé sur une autre machine.