0% ont trouvé ce document utile (0 vote)
134 vues11 pages

Introduction à RMI en Java

Transféré par

Mohamed Amine SOUIDI
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
134 vues11 pages

Introduction à RMI en Java

Transféré par

Mohamed Amine SOUIDI
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Chapitre

Appel de méthodes distantes : RMI

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 est une solution pour l’invocation de méthodes Java à distance. Des implantations alternatives et
open-source de RMI existent, parmi eux : NinjaRMI (Berkley) et Jeremie (ObjectWeb).
Java RMI est un mécanisme de RPC dédié aux objets Java, il génère automatiquement des stubs côté client
et des squelettes côté serveur.

1. 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éthode 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 communication, d'exécution, de
renvoi et de réception du résultat.

2. Les différentes étapes pour créer un objet distant 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
• 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 noms 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.

3. 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éée et
enregistrée dans le registre RMI.

3.1. 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 [Link]. 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 distante 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
[Link].

Exemple ( code Java 1.1 ) :


package [Link];

import [Link].*;

public interface Information extends Remote {

public String getInformation() throws RemoteException;

3.2. 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 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 capable 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 :

[Link]
[Link]
[Link]
[Link]

Comme indiqué dans l'interface, 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 ( code Java 1.1 ) :


package [Link];

import [Link];
import [Link];

public class InformationImpl extends UnicastRemoteObject implements


Information {

private static final long serialVersionUID = 2674880711467464646L;

protected InformationImpl() throws RemoteException {


super();
}

public String getInformation() throws RemoteException {


[Link]("Invocation de la méthode getInformation()");
return "bonjour";
}
}

3.3. 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
• l'enregistrement de la classe dans le registre de noms RMI

3.3.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.
Exemple ( code Java 1.1 ) :
public static void main(String[] args) {
try {
if ([Link]() == null) {
[Link](new RMISecurityManager());
}
} catch (Exception e) {
[Link]();
}
}

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


[Link] de la JVM.

3.3.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

Exemple ( code Java 1.1 ) :


public static void main(String[] args) {
try {
if ([Link]() == null) {
[Link](new RMISecurityManager());
}

InformationImpl informationImpl = new InformationImpl();


} catch (Exception e) {
[Link]();
}
}

3.3.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 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.

Exemple ( code Java 1.1 ) :


public static void main(String[] args) {
try {
if ([Link]() == null) {
[Link](new RMISecurityManager());
}

InformationImpl informationImpl = new InformationImpl();


String url = "rmi://" + [Link]().getHostAddress() +
"/TestRMI";
[Link]("Enregistrement de l'objet avec l'url : " + url);
[Link](url, informationImpl);

[Link]("Serveur lancé");
} catch (RemoteException e) {
[Link]();
} catch (MalformedURLException e) {
[Link]();
} catch (UnknownHostException e) {
[Link]();
}
}

3.3.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 (rmiregistry) 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


[Link]. Cette méthode attend en paramètre un numéro de port.

Exemple ( code Java 1.1 ) :


package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];

public class LanceServeur {

public static void main(String[] args) {


try {
[Link](1099);

[Link]("Mise en place du Security Manager ...");


if ([Link]() == null) {
[Link](new RMISecurityManager());
}

InformationImpl informationImpl = new InformationImpl();


String url = "rmi://" + [Link]().getHostAddress() +
"/TestRMI";
[Link]("Enregistrement de l'objet avec l'url : " + url);
[Link](url, informationImpl);

[Link]("Serveur lancé");
} catch (RemoteException e) {
[Link]();
} catch (MalformedURLException e) {
[Link]();
} catch (UnknownHostException e) {
[Link]();
}
}
}

4. Le développement coté client

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

4.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 identiques à 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.

Exemple ( code Java 1.1 ) :


public static void main(String[] args) {
if ([Link]() == null) {
[Link](new RMISecurityManager());
}
}

4.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.
Exemple ( code Java 1.1 ) :
public static void main(String[] args) {

if ([Link]() == null) {
[Link](new RMISecurityManager());
}

try {
Remote r = [Link]("rmi://[Link]/TestRMI");
} catch (Exception e) {
[Link]();
}

4.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.

Une fois le cast réalisé, il suffit simplement d'appeler la méthode.

Exemple ( code Java 1.1 ) :


package [Link];

import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];

public class LanceClient {

public static void main(String[] args) {


[Link]("Lancement du client");
if ([Link]() == null) {
[Link](new RMISecurityManager());
}
try {
Remote r = [Link]("rmi://[Link]/TestRMI");
[Link](r);
if (r instanceof Information) {
String s = ((Information) r).getInformation();
[Link]("chaine renvoyee = " + s);
}
} catch (MalformedURLException e) {
[Link]();
} catch (RemoteException e) {
[Link]();
} catch (NotBoundException e) {
[Link]();
}
[Link]("Fin du client");
}
}
4.4. L'appel d'une méthode distante dans une applet

L'appel d'une méthode distante est le même dans une application et dans une applet.

Seule la mise en place d'un security manager dédié dans les applets est inutile car elles utilisent
déjà un sécurity manager (AppletSecurityManager) qui autorise le chargement de classes
distantes.

Exemple ( code Java 1.1 ) :


package [Link];

import [Link].*;
import [Link].*;
import [Link].*;

public class AppletTestRMI extends Applet {

private String s;

public void init() {

try {
Remote r = [Link]("rmi://[Link]/TestRMI");

if (r instanceof Information) {
s = ((Information) r).getInformation();
}
} catch (Exception e) {
[Link]();
}
}

public void paint(Graphics g) {


[Link](g);
[Link]("chaine retournée = "+s,20,20);
}
}

5. La génération de la classe stub

Pour générer la classe stub, il suffit d'utiliser l'outil rmic fourni avec le JDK en lui donnant en
paramètre le nom pleinement qualifié de la classe.

Attention la classe doit avoir été compilée : rmic a besoin du fichier .class.

Exemple ( code Java 1.1 ) :


rmic [Link]

rmic va générer et compiler la classe stub sous le nom InformationImpl_Stub.class. Cette classe
sera utilisée par la partie cliente pour invoquer l'objet distant correspondant.

6. La mise en œuvre des objets RMI

La mise en oeuvre et l'utilisation d'objets distants avec RMI nécessite plusieurs étapes :
1. Démarrer le registre RMI sur le serveur soit en utilisant le programme rmiregistry livré
avec le JDK soit en exécutant une classe qui effectue le lancement.
2. Exécuter la classe qui instancie l'objet distant et l'enregistre dans le serveur de noms RMI
3. Lancer l'application ou l'applet pour tester.

6.1. Le lancement du registre RMI

La commande rmiregistry est fournie avec le JDK. Il faut la lancer en tâche de fond :

Sous Unix : rmiregistry&

Sous Windows : start rmiregistry

Ce registre permet de faire correspondre un objet à un nom et inversement. C'est lui qui est
sollicité lors d'un appel aux méthodes [Link]() et [Link]()

6.2. L'instanciation et l'enregistrement de l'objet distant

Il faut exécuter la classe qui va instancier l'objet distant et l'enregistrer sous son nom dans le
registre précédemment lancé.

Pour ne pas avoir de problème, il faut s'assurer que toutes les classes utiles (la classe de l'objet
distant, l'interface qui définit les méthodes) sont présentes dans un répertoire défini dans le
classpath.

Si un gestionnaire de sécurité est mis en place, il faut définir un fichier qui va contenir la politique
de sécurité qu'il doit mettre en oeuvre.

Exemple ( code Java 1.1 ) : le fichier ma_policy_serveur


grant{
permission [Link] "localhost:1099", "connect,
resolve";
permission [Link] "*:1024-", "connect, resolve";
permission [Link] "*:1024-", "accept, resolve";
};

Les permissions définies concernent les permissions de connexions par socket au serveur.

Lors du lancement du serveur, l'option [Link] permet de préciser le fichier qui sera
utilisé par le gestionnaire de sécurité.

Exemple ( code Java 1.1 ) : le fichier ma_policy_serveur


C:\Users\Jean Michel\workspace\TestRmiServer>java -cp bin -
[Link]
=ma_policy_serveur [Link]
Mise en place du Security Manager ...
Enregistrement de l'objet avec l'url : rmi://[Link]/TestRMI
Serveur lancé
6.3. Le lancement de l'application cliente

L'archive de la partie cliente doit contenir le client, l'interface de l'objet distant et le stub qui a été
généré par rmic.

Exemple :
C:\temp>jar -tf [Link]
META-INF/[Link]
com/jmdoudoux/test/rmi/[Link]
com/jmdoudoux/test/rmi/InformationImpl_Stub.class
com/jmdoudoux/test/rmi/[Link]

Le client qui invoque l'objet distant est lancé de manière classique.

Exemple :
C:\temp>java -jar [Link]
Lancement du client
InformationImpl_Stub[UnicastRef [liveRef:
[endpoint:[[Link]:62802](remote),ob
jID:[7b7739e4:135b4a87a5e:-7fff, -3323459310870193038]]]]
chaine renvoyee = bonjour
Fin du client

Si le serveur n'est pas démarré, une exception est levée

Exemple :
C:\temp>java -jar [Link]
Lancement du client
[Link]: Connection refused to host: [Link]; nested
excepti
on is:
[Link]: Connection timed out: connect
at [Link](Unknown Source)
at [Link](Unknown
Source)
at [Link](Unknown Source)
at [Link](Unknown Source)
at [Link].RegistryImpl_Stub.lookup(Unknown Source)
at [Link](Unknown Source)
at [Link]([Link])
Caused by: [Link]: Connection timed out: connect
at [Link](Native Method)
at [Link](Unknown Source)
at [Link](Unknown
Source)
at [Link](Unknown Source)
at [Link](Unknown Source)
at [Link](Unknown Source)
at [Link](Unknown Source)
at [Link](Unknown Source)
at [Link].<init>(Unknown Source)
at [Link].<init>(Unknown Source)
at
[Link](Unknown S
ource)
at
[Link](Unknown S
ource)
... 7 more
Fin du client

La partie client peut être lancée avec un gestionnaire et une politique de sécurité associée.

Exemple ( code Java 1.1 ) :


C:\temp>java -jar -[Link]=ma_policy_client [Link]
Lancement du client
InformationImpl_Stub[UnicastRef [liveRef:
[endpoint:[[Link]:62802](remote),ob
jID:[7b7739e4:135b4a87a5e:-7fff, -3323459310870193038]]]]
chaine renvoyee = bonjour
Fin du client

Si le gestionnaire est activé sans politique de sécurité associée alors la connexion au serveur est
impossible.

Exemple ( code Java 1.1 ) :


C:\temp>java -jar -[Link] [Link]
Lancement du client
Exception in thread "main" [Link]: access
denied (
"[Link]" "[Link]:1099" "connect,resolve")
at [Link](Unknown
Source)
at [Link](Unknown Source)
at [Link](Unknown Source)
at [Link](Unknown Source)
at [Link](Unknown Source)
at [Link](Unknown Source)
at [Link].<init>(Unknown Source)
at [Link].<init>(Unknown Source)
at
[Link](Unknown S
ource)
at
[Link](Unknown S
ource)
at [Link](Unknown Source)
at [Link](Unknown
Source)
at [Link](Unknown Source)
at [Link](Unknown Source)
at [Link].RegistryImpl_Stub.lookup(Unknown Source)
at [Link](Unknown Source)
at [Link]([Link])

Vous aimerez peut-être aussi