Les Remote Method Invocations de Java
|
Introduction
Nous avons vu avec les chapitres sur TCP/UDP, des mecanismes permettant
d'effectuer des communications sur un reseau heterogene. Ces mecanismes
sont pertinents lorsque l'on veut ecrire une application repartie relativement
simple faites de programmes plutot independants ayant ponctuellement a
se communiquer des informations (sous formes d'une serie de bits a lire
ou ecrire selon un protocole a specifier).
A un niveau superieur, nous trouvons des bibliotheques style MPI
qui permettent de creer des applications reparties plus complexes basees
sur l'echange de messages structures.
A un niveau encore superieur, on trouve les RPC (Remote Procedure
Call) qui permettent de concevoir une application repartie en faisant directement
des appels a une procedure distante comme si elle etait locale. Le systeme
se charge de transmettre les differentes donnees de facon transparente.
Il code ces donnees par un format commun de representation (XDR).
Les RMI de Java ont pour but d'utiliser des methodes d'objets
distants. Le developpement des RMI a ete grandement facilite par la presence
des machines virtuelles Java qui permettent de considerer que l'application
distribuee que l'on ecrit va fonctionner sur un parc homogene de machines.
Structure generale
Les RMI de Java ont ete definis en couches a la maniere du modele ISO pour
les reseaux ou plus precisement inspiree de celle de Corba. On considere
ici trois couches independantes definies chacunes par une interface et
un protocole.
NB : "souche" est une traduction de "stub" (on retrouve
la structure utilisee par la JNI). |
 |
Proprietes
-
Les objets distants devront tous etre decrits par une interface. Toutes
ces interfaces etendent d'une facon ou d'une autre l'interface java.rmi.remote.
-
Un objet distant peut etre un parametre d'entree ou etre retourne par une
methode.
-
Les clients d'objets distants voient l'interface de cet objet, pas la classe
qui implemente l'interface.
-
Des exceptions supplementaires sont generees par les objets distants.
-
Contrairement au modele non-distribue, les parametres d'entree ou de sortie
d'un objet distant sont passes par copie. Par contre, on ne connait l'objet
a distance que par sa reference.
Schema type d'une application RMI
Par exemple, on peut definir l'interface suivante et son implantation
:
Interface : Message_rmi.java
|
Implementation de l'interface : Message_rmiImpl.java
|
public interface
Message_rmi
extends java.rmi.Remote
{
} |
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
public class Message_rmiImpl
extends UnicastRemoteObject
implements Message_rmi
{
private String name;
// constructeur
public Message_rmiImpl (String
s) throws RemoteException
{ super(); name = "Oh le joli message a distance depuis" + s;
}
// affiche effectivement le message
public String message() throws
RemoteException
{ return name ; }
// change effectivement le message
public void change_message(String
mess) throws RemoteException
{ name=mess ; }
// le main
public static void main(String args[])
{
// Cree et installe un security manager
System.setSecurityManager(new RMISecurityManager());
try {
Message_rmiImpl obj = new
Message_rmiImpl("mon_serveur");
Naming.rebind("//machine_locale/"
+ "mon_serveur", obj );
System.out.println("mon_serveur est enregistre.");
} catch (Exception e) {
System.out.println("Erreur : " + e.getMessage());
e.printStackTrace();
}
}
} |
Remarques :
-
Les classes qui implementent les objets doivent heriter soit de java.rmi.server.RemoteObject,
de java.rmi.server.RemoteServer ou
de java.rmi.server.UnicastRemoteObject.
-
Le security manager garantit qu'il n'y aura pas d'operations illegales
d'effectuees.
-
On constate qu'apres avoir cree un objet de la classe Message_rmiImpl,
on effectue une operation rebind sur
celui-ci. Cette operation sert a enregistrer cet objet aupres d'un demon
(rmiregistry) qui recoit les appels RMI venant du reseau. Cette
operation est une methode de la classe Naming.
Sur notre exemple, l'appel sur un autre site se fera par exemple avec
la classe suivante :
import java.rmi.*;
public class appel
{
public static void main(String argv[])
{ String url="rmi://machine_distante_ou_tourne_Message_rmiImpl/mon_serveur")
;
try
{
Message_rmi obj = (Message_rmi)Naming.lookup(url);
System.out.println(obj.message()
);
obj.change_message(String("Au revoir."))
;
System.out.println(obj.message()
);
} catch (Exception e)
{
System.out.println("Appel exception: " + e.getMessage());
e.printStackTrace();
}
}
} |
Remarques :
-
La fonction lookup de la classe Naming
va demander au demon RMI qui tourne sur la machine specifiee de renvoyer
les informations sur l'objet mon_serveur de classe Message_rmi.
-
Une fois cette operation faite, l'objet se manipule comme s'il etait local.
Compilation type
javac *.java
rmic Message_rmiImpl
Remarque :
rmic genere automatiquement les classes squelette et souche de l'application.
Le lancement
Lancer le demon qui va intercepter les demandes du reseau (site 1): rmiregistry
&
Lancer la classe implementant l'application (site 1): java Message_rmiImpl
&
bash$ rmiregistry &
[1] 5788
bash$ java Message_rmiImpl &
[2] 5749
mon_serveur est enregistre.
bash$ |
Lancer le programme d'appel (site 2) : java appel &
Resultat sur le site 2
bash$ java appel
Oh le joli message a distance depuis mon_serveur
Au revoir.
bash$ |
Resume de ce qui'il faut retenir
-
Pour atteindre un objet quelque part sur le reseau par RMI, cet objet doit
avoir une interface d'un cote et une implementation de l'autre.
-
Une classe voulant atteindre l'objet distribue, peut le faire en obtenant
une reference avec l'url de l'objet.
-
Pour que l'objet distribue s'execute, il faut d'abord lancer un demon (le
rmiregistry), puis lancer le programme.
Ph. RIS 1997