| 
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 generaleLes 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 {
 
} catch (Exception e) {Message_rmiImpl obj = new
Message_rmiImpl("mon_serveur"); 
Naming.rebind("//machine_locale/"
+ "mon_serveur", obj );
 System.out.println("mon_serveur est enregistre.");
 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); 
} catch (Exception e)System.out.println(obj.message()
);
 obj.change_message(String("Au revoir."))
;
 System.out.println(obj.message()
);
 {
 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