4.1 Aperçu des paquetages
– 4 paquetages pour les rmi : – java.rmi,
– java.rmi.server, – java.rmi.registry, – java.rmi.dgc
– java.rmi: classes, interfaces et exceptions coté client.
– java.rmi.server : classes, interfaces et exceptions coté serveur. Classes utilisées lorsqu’on écrit des objets distants utilisés par des clients.
– java.rmi.registry: classes, interfaces et exceptions utilisées pour localiser et nommer des objets distants.
– java.rmi.dgc : gestion du ramasse-miettes distribué (dgc, ou Distributed Grabage Collector).
VII.4 – Implantation 141 – ☛ Dans la suite, et conformément à la documentation Sun, on utilisera l’adjectif distant en se référant implicitement à un serveur et l’adjectif local en se référant à un client.
4.2 Implantation du serveur
– Pour créer un nouvel objet distant, on définit une interface qui étend java.rmi.Remote.
– L’interface Remoten’a aucune méthode. Elle agit comme un marqueur d’ob- jets distants.
– L’interface enfant de Remoteque l’on définit détermine quelles méthodes de l’objet distant à créer peuvent être appelées par les clients.
– Seules les méthodes publiques déclarées dans une interface distante peuvent être appelées de manière distante.
– Chaque méthode de l’interface enfant de Remote définie par le pro- grammeur doit déclarer lever l’exception java.rmi.RemoteException. – Exemple d’une interface pour un “Hello World” distant. Cette interface a
une seule méthode, parler() import java.rmi.*;
public interface DoueDeParole extends Remote {
public String parler() throws java.rmi.RemoteException; }
– Après avoir défini une interface distante, il faut définir une classe qui implante cette interface et étend java.rmi.UnicastRemoteObject. – La classe UnicastRemoteObject fournit un certain nombre de méthodes qui
se chargent des détails de la communication distante. – En particulier, il y a le découpage et le rassemblement.
– Découpage (marshaling) : conservion des arguemnts et des valeurs de retour en un flux d’octets qui peuvent être envoyés à travers le réseau.
– Exemple de BashoServeur, une classe qui implante l’interface distante DoueDeParole et qui étend UnicastRemoteObject
import java.rmi.*;
import java.rmi.server.*; import java.net.*;
public class BashoServeur extends UnicastRemoteObject implements DoueDeParole { public BashoServeur() throws RemoteException {
}
public String parle() throws RemoteException {
return "La cloche du temple s’est tue " + "\n" "Dans le soir, le parfum des fleurs " + "\n" "En prolonge le tintement. " + "\n" "Matsuo Basho (1644-1694)" ;
}
public static void main(String args[]) { try {
BashoServeur b = new BashoServeur(); Naming.rebind("MatsuoBasho", b);
System.out.println("Serveur BahoServeur pret."); } catch (RemoteException re) {
System.out.println("Exception ds BashoServeur.main() : " + re); } catch (MalformedURLException re) {
System.out.println("MalformedURLException ds BashoServeur.main() : " + re);
} }// main() }
– Le constructeur BashoServeur() appelle le constructeur par défaut. Pour une classe Java locale, ceci n’a pas besoin d’etre écrit. Ici, on doit déclarer que toute méthode lève RemoteException.
– Notez bien qu’ici le code de la méthode distante quoiDire() n’est pas différent de celui qui serait écrit pour une application entièrement locale.
–
➶
Ceci est un gros avantage des RMI : les aspects distants sont pour la plupart transparents pour le programmeur.– Notez que les méthodes main()et BashoServeur()ne seront pas disponibles de manière distante. Seule quoiDire() l’est (parce que figurant dans une interface Remote).
– Le constructeur est trivial mais doit figurer, afin de déclarer qu’il lève une RemoteException.
– Il y a enregistrement de l’objet BashoServeur via un Naming.rebind(). Cette méthode place les objets dans un registre et leur associe un nom fourni en paramètre.
– Un client peut ensuite requérir cet objet par son nom ou obtenir une liste d’objets disponibles.
VII.4 – Implantation 143
4.3 Génération des souche et squelette
– On génère la souche (stub) et le squelette (skeleton) via rmic, que l’on applique aux .class Par ex.
/home/mounier > rmic BashoServeur /home/mounier > ls Doue* BashoServeur*
BashoServeur.class BashoServeur_skel.class DoueDeParole.class BashoServeur.java BashoServeur_stub.class DoueDeParole.java – Arguments : rmic BashoServeur -d -classpath JavaProgs/Tests L’option
-dva mettre le .class dans le répertoire où le source est trouvé (par défaut, le .class est placé dans le répertoire courant).
4.4 Lancement du serveur
– Pour lancer le serveur :
– On lance d’abord le serveur de registre, avec lequel le serveur dialogue : rmiregistry &(ou start rmregistry sous DOS). Il écoute sur le port 1099 par défaut. Pour qu’il écoute sur un autre port : rmiregistry 2048 &
– On lance ensuite le serveur,
/home/mounier > java BashoServeur & Serveur BashoServeur pret.
4.5 Implantation du client
– Pour qu’un client appelle une méthode distante, il doit récupérer une réfé- rence à un objet distant.
– Pour cela, il récupère un objet distant en demandant au serveur de recher- cher dans un registre. La demande s’effectue au travers de la méthode lookup(String name)qu’appelle le client.
– Le schéma de nommage dépend du registre utilisé. La classe Naming du paquetage java.rmi fournit un schéma fondé sur des URL pour localiser des objets.
– L’obtention de référence distante se fera alors par :
Object o1 = Naming.lookup("rmi://sunsite.unc.edu/MatsuoBasho"); Object o2 = Naming.lookup("rmi://sunsite.unc.edu:2048/MatsuoBasho"); – Le champ de protocole est ici rmi, qui signifie que l’URL référence un objet
distant.
– Le champ fichier (ici MatsuoBasho) spécifie le nom de l’objet distant. – Les champs de nom de machine et de numéro de port optionnel sont in-
– Puisque la méthode lookup() renvoie un Object, il faut effectuer une conversion de type (cast) en le type d’interface distante que l’objet distant implante (et non la classe elle-même, cachée des clients) : DoueDeParole b = (DoueDeParole) Naming.lookup("MatsuoBasho") ;
– Exemple de client associé à BashoServeur : import java.rmi.*;
public class BashoClient {
public static void main(String args[]) {
System.setSecurityManager(new RMISecurityManager()); try {
DoueDeParole b = (DoueDeParole) Naming.lookup("MatsuoBasho"); String message = b.parle();
System.out.println("BashoClient : " + message); } catch (Exception e) {
System.out.println("Exception dans BashoClient.main() : " + e);
} } }