Introduction
Remote Method Invocation (R.M.I.,
Invocation de Méthode Distante): Solution Sun au problème de la gestion des objets
distribués.
Grâce aux R.M.I. un programme Java
pourra appeler certaines méthodes d'objets existant sur un serveur distant (objets
distants).
Les objets distants sont utilisés
dans le programme client de manière semblable à l'utilisation d'objets locaux.
En contrepartie, certaines contraintes de programmation devront être respectées.
-> Un moyen simple pour définir
protocoles personnalisés et programmes client-serveur à moindre effort.
-> Un moyen simple pour déporter
des calculs sur une machine distante et limiter les transferts d'informations.
Disponible depuis le J.D.K. 1.1.
Remanié avec Java 2.
Mise en
uvre
Architecture
Une application client-Serveur
utilisant les R.M.I. met en uvre 3 composantes logicielles:
à
l'enregistrement des objets distants du serveur accessibles aux clients,
à
l'association de noms à ces objets permettant ainsi de le référencer.
Les connexions et transferts
d'informations sont entièrement pris en charge par Java.TCP/IP est utilisé via un
protocole dédié (Java Remote Method Protocol, JRMP) sur le port 1099 par défaut.
A partir de Java 2 Version 1.3, un
nouveau protocole est utilisé : RMI-IIOP (Internet Inter-ORB Protocol). Celui-ci est
normalisé par l'Object Management Group (OMG).
-> Rapprochement vers CORBA.
Packages
Quatre packages Java pour
l'utilisation des R.M.I.:
java.rmi: Définition des classes, interfaces et exceptions qui
concernent le client (accès à des méthodes distantes sans en écrire).
java.rmi.server: Définition des classes, interfaces et exceptions qui
concernent le serveur (création d'objets distants à l'intention de clients).
java.rmi.registry: Localisation et dénomination des objets distants
(publication des objets distants accessibles).
java.rmi.dgc: Ramasse miettes distribué (récupération automatique de
la mémoire qui n'est plus utilisée).
Implantation
effective
Un "objet distant"
est un objet dont les méthodes peuvent être appelées par d'autres machines virtuelles
que celle qui l'abrite.
Une classe Java autorisant des appels
distants devra implanter (Exemple)
une "interface distante"
spécifiant quelles sont les méthodes accessibles pour ces appels distants.
Cette interface devra dériver elle-même de l'interface java.rmi.Remote (Exemple).
La classe distante (instanciant l'objet distant) programmée devra dériver de java.rmi.server.UnicastRemoteObject.
Les clients pourront ensuite utiliser, de manière quasi transparente (Exemple), les objets distants instanciant cette classe
comme s'ils étaient des objets locaux à leurs systèmes.
Un objet distant peut implanter une ou
plusieurs interfaces distantes.
ATTENTION: En Java,
les passages de paramètres sont effectués par valeur. Il en est de même pour les
méthodes distantes utilisées avec les R.M.I.
Une petite difficulté est que passer un objet (en fait il s'agit d'un pointeur) par
valeur correspond à un passage par référence pour les méthodes classiques tandis que
pour les méthodes distantes, le passage en paramètre d'un objet entraînera la
reconstruction complète de l'objet à distance et donc restituera un pur passage par
valeur.
ATTENTION: Le passage
en paramètre d'objets dans les appels de méthodes distantes nécessite que ces objets
implantent l'interface Serializable pour que ces objets soient transférables sur le
réseau.
Le Naming des
objets
La publication des objets d'un serveur
est réalisée via un processus d'enregistrement et de naming de ces objets au sein du
programme médiateur rmiregistry.
Cette application fonctionnant sur une
machine hôte permet l'enregistrement d'objets par attribution à chacun d'eux d'un nom
sous forme d'une chaîne de caractères.
Ce nom désigne l'objet à tout
programme client à même de l'exploiter par référenciation au moyen d'une convention de
type URL. Par exemple, rmi://raphaello.univ-fcomte.fr/salut désigne un objet de classe à
priori inconnue référencé avec le nom salut sur la machine raphaello.univ-fcomte.fr.
Architecture
interne
Pour l'utilisateur, les connexions
semblent s'effectuer directement entre le client et le serveur. Dans la pratique, les
données opèrent un parcours à travers un certain nombre de couches, ces couches ayant
pour but un maximum de compatibilité entre les programmes et les versions de Java.
Deux des couches traversées sont le
Stub et le Skeleton qui sont utilisés respectivement sur le client avec un rôle de proxy
et sur le serveur avec pour rôle la gestion des communications vers le Stub des clients.
Le Skeleton n'est plus nécessaire
depuis Java 2, mais reste nécessaire si on souhaite la compatibilité avec Java 1.1.
Ces deux couches prennent la forme de
classes Java compilées (Exemple). Le serveur
devra avoir accès aux Stubs et aux Skeletons des classes implantées. Seules les Stubs
doivent être accessibles aux clients.
Il existe d'autres couches (Remote
Reference Layer, Transport Layer) non décrites ici et qui ne sont pas caractérisées par
une implantation sous la forme explicite de classes.
Exemple de processus de programmation
Partie serveur
Définition d'une interface héritant de java.rmi.Remote: Identification des objets distants et définition de leurs
méthodes accessibles à distance.
Exemple:
import java.rmi.* ;
public interface Bonjour extends Remote {
public String bonjourDistant()
throws RemoteException ;
} |
Bonjour.java |
Définition d'une classe
implantant cette interface distante et héritant de java.rmi.server.UnicastRemoteObject.
Exemple:
import java.rmi.* ;
import java.rmi.server.* ;
import java.net.* ;
/* ************************************ */
/* Extension de UnicastRemoteObject */
/* Implantation de l'interface distante */
/* ************************************ */
public class ImplanteBonjour
extends UnicastRemoteObject
implements Bonjour {
/* ************************************ */
/* Constructeur obligatoire
*/
/* avec appel a super() et
*/
/* gestion d'une RemoteException */
/* ************************************ */
public ImplanteBonjour()
throws RemoteException {
super() ;
}
/* ************************************ */
/* Fonction de l'interface distante */
/* ************************************ */
public String bonjourDistant()
throws RemoteException {
return("Salut!!!") ;
}
/* ************************************ */
/* Application serveur assurant */
/* la creation d'un objet distant, */
/* sa referenciation avec nomage */
/* sur la rmiregistry de l'hote local */
/* ************************************ */
public static void main(String [] args) {
try {
ImplanteBonjour ib =
new ImplanteBonjour();
Naming.rebind("salut",ib) ;
System.out.println("Prêt"); }
catch (RemoteException re) {
System.out.println(re) ; }
catch(MalformedURLException e) {
System.out.println(e) ; }
}
} |
ImplanteBonjour.java |
Cette classe possède plusieurs
méthodes. La seule utilisable à distance par le client est String bonjourDistant() qui renvoie la chaîne de caractère constante
"Salut!!!". Les autres méthodes sont un constructeur dont le seul but est de
rendre compte d'une éventuelle RemoteException via l'appel au constructeur de la
superclasse (super()) et une méthode main (associée à une application java)
qui instancie un ImplanteBonjour et l'associe au nom "salut" dans le registre de
nommage java.rmi.Naming (mémorisation des noms des objets disponibles).
Exécution du compilateur rmic pour générer
les stubs et les skeletons nécessaires au programme.
Lancement en ligne de commande du registre Naming.
Sous UNIX |
rmiregistry & |
sous Windows |
start rmiregistry |
Lancement du serveur (Attention: Si nécessaire, ajuster
le CLASSPATH pour qu'il indique le répertoire contenant les classes afférentes au
serveur).
Partie cliente
Dans les cas simples,
la programmation d'une seule classe est nécessaire à l'implantation d'un client
d'accès aux objets d'un serveur R.M.I.
Exemple:
import java.rmi.* ;
/* ************************************ */
/* Une classe toute simple
*/
/* pour l'application cliente
*/
/* ************************************ */
public class ClientBonjour {
/* ************************************ */
/* Application cliente assurant */
/* la recuperation avec instanciation */
/* d'un object et cast vers l'interface */
/* Bonjour d'une reference a un objet */
/* distant et appelle a la methode */
/* distante de cet objet
*/
/* ************************************ */
public static void main(String [] args) {
try {
Bonjour b =(Bonjour) Naming.
lookup("salut");
System.out.println(
b.bonjourDistant()) ; }
catch (Exception e) {
System.out.println(e) ; }
}
} |
ClientBonjour.java |
Le client fait appel à la fonction
membre static Naming.lookup de la classe Naming pour générer une instance de l'objet distant et il le
convertit vers l'interface distante désirée. Il ne reste ensuite qu'à utiliser les
méthodes désirées de l'objet obtenu.
Répartition des
fichiers entre client et serveur
Les postes clients et serveurs sont
par essence généralement des machines différentes.
Si on envisage la programmation d'Applets, une troisième machine intervient dans
l'architecture.
-> Les fichiers classe pourront avoir à être placés sur trois machines différentes.
- Interface(s) distante(s)
- Classes nécessaires au démarrage du client
- Classes du serveur
- Interface(s) distante(s)
- Classes implantant les interfaces distantes
- Stubs
- Interface(s) distante(s)
- Stubs
- Skeletons (J.D.K. 1.1)
Exemple
de programmation WEB d'une applet avec RMI (Nécessite Java 2).
Classes
et méthodes usuelles
Méthodes utilisées dans la classe
java.rmi.Naming
Dans la partie serveur:
public static void
bind(String name, Remote obj)
throws AlreadyBoundException, MalformedURLException, UnknownHostException, RemoteException
Association d'un nom et d'un
objet distant. L'association échoue si le nom existe déjà.
public static void
unbind(String name)
throws RemoteException, NotBoundException, MalformedURLException, UnknownHostException
Suppression de l'association entre un
nom et un objet distant
public static void
rebind(String name, Remote obj)
throws RemoteException, MalformedURLException, UnknownHostException
Association d'un nom et d'un objet
distant. Si le nom existe déjà l'association réussit et l'objet associé au nom est
changé.
Dans la partie cliente:
public static Remote
lookup(String name)
throws NotBoundException, MalformedURLException, UnknownHostException, RemoteException
Extraction d'une interface Remote
contruite à partir de l'objet associé au nom. La chaîne donnée est formatée comme une
URL avec le protocole rmi, puis le nom de la machine sur laquelle est enregistré l'objet
et enfin le nom local associé à l'objet.
Exemple:
rmi://raphaello.univ-fcomte.fr/salut
Autres classes et interfaces
Les autres classes et interfaces
utilisées présentent des méthodes qui ne seront pas décrites ici.
Exemple
Programmation
WEB d'une applet avec RMI (Java 2).
Limitations
des R.M.I.
Les R.M.I. sont strictement
limitées à Java (sauf implantations particulières), apportant la portabilité entre
systèmes, mais ne sont pas adaptées aux environnements de programmation mixant les
langages.
Dans ce cadre on préférera
l'utilisation de CORBA (Common Object Request Broker Architecture) qui gère
l'interopérabilité entre langages et entre systèmes et qui existe aussi en Java.
Exercices
Partage
d'ensembles de coordonnées 2D
On souhaite stocker sur un serveur de
données un ensemble de coordonnées 2D décrivant les positions d'un certain nombre de
véhicules dans le plan.
Ce serveur devra inclure les
fonctionnalités suivantes:
- accès au nombre de positions
- accès au nom d'une position
- accès en lecture aux positions
- création d'une nouvelle position et nommage
- destruction d'une position
- accès en écriture aux positions
a) Ecrire l'application serveur.
b) Ecrire une application cliente
ayant pour but de créer une nouvelle position.
c) Ecrire une application cliente
ayant pour but de détruire une position.
d) Ecrire une application cliente
ayant pour but de modifier une position.
e) Ecrire une application cliente
ayant pour but de lire et d'afficher toutes les positions.
Solution
Calcul
parallèle
On désire concevoir une application
client-serveur à même de réaliser un calcul parallèle pour la multiplication d'un
ensemble de n vecteurs à 4 dimensions par une matrice 4x4.
a) Ecrire une application serveur
permettant de réaliser le produit de un vecteur par une matrice et rendant le résultat.
b) Ecrire une application serveur
permettant de réaliser le produit de nv vecteurs par une matrice M et rendant les
résultats.
c) Ecrire une application cliente
initialisant n vecteurs et distribuant leurs produits par une matrice M sur ns serveurs
disponibles.
Solution |