06-01-2009
 
  Accueil arrow Tutoriels arrow Java arrow RMI    
Accueil
Travaux
Mon CV
Tutoriels
Histoire
Contact


RMI Convertir en PDF Version imprimable
Appréciation des utilisateurs: / 53
FaibleMeilleur 

RMI (Remote Method Invocation) est une API Java permettant de manipuler des objets distants (objet qui existe dans un autre espace adresse soit dans la même machine soit dans une machine différente) de manière transparente pour l'utilisateur, c'est-à-dire de la même façon que si l'objet était sur la machine virtuelle. Dans les premières version de JAVA, RMI est une solution pure Java, contrairement à la norme Corba de l'OMG (Object Management Group) permettant de manipuler des objets à distance avec n'importe quel langage et sur n’importe quelle plate-forme. Corba est toutefois beaucoup plus compliqué à mettre en oeuvre, c'est la raison pour laquelle de nombreux développeurs se tournent généralement vers RMI d’ou la nécessité d'évoluér l’API pour qu’elle devienne compatible avec CORBA. En particulier, elle prend en charge des appels sous forme de IIOP (Internet Inter-ORB Protocol) un protocole de CORBA.

Architecture de RMI

En RMI la transmission de données se fait à travers un système de couches, basées sur le modèle OSI afin de garantir une interopérabilité. Quant aux connexions, elles sont effectuées grâce à un protocole propriétaire JRMP (Java Remote Method Protocol) basé sur TCP/IP.

Couche RMI
  • Le stub (souche) et le skeleton (traduisez squelette), respectivement sur le client et le serveur, assurent la conversion des communications avec l'objet distant.
  • La couche de référence (RRL, remote Reference Layer) est chargée du système de localisation afin de fournir un moyen aux objets d'obtenir une référence à l'objet distant. On l'appelle généralement l’annuaire RMI.
  • La couche de transport permet d'écouter les appels entrants ainsi que d'établir les connexions et le transport des données sur le réseau.

Lorsqu'un client désire invoquer une méthode d'un objet distant, il effectue les opérations suivantes :

Architecture RMI

Il localise l'objet distant grâce à un service d’annuaire (Registry)

1- Il obtient dynamiquement une image virtuelle de l'objet distant (stub ).
2- Le stub possède exactement la même interface que l'objet distant.
3- Le stub sérialise les appels de la méthode distante, puis les transmet au serveur sous forme de flux de données. Ce qu’on appel "marshalise".
4- Le Skeleton"déserialise" les données envoyées par le stub ("démarshalise"), puis appelle la méthode en local
5- Le Skeleton récupère les résultats puis les marshalisent.
6- Le stub démarshalise les données provenant du Skeleton et les transmet au client

Notons qu'a partir de la version 1.2, le Skeleton a été remplacé par un Stub.

Pour réaliser un programme RMI, on doit absolument passer par 5 étapes essentielles:

1- Définir l'interface pour la classe distante qui hérite de l'interface Remote et déclarer les méthodes publiques globales de l'objet. De plus ces méthodes doivent pouvoir lancer une exception de type RemoteException (BonjourInterface). Une interface, littéralement parlant est un dispositif ou un système que les entités indépendantes emploient pour agir l'un sur l'autre. En java ou autre langage qui utilise des interfaces, c’est une définition d’un protocole comportementale qui peut être mis en application par n'importe quelle classe dans n'importe quel niveau hiérarchique de cette dernière. En plus clair, les interfaces sont utilisées pour :

  • Détecter les similitudes parmi des classes sans forcer artificiellement leurs rapports.
  • Déclaration des méthodes qu'on s'attend à ce qu'une ou plusieurs classes peuvent implémenter.
  • Indiquer un objet d’interface sans indiquer sa classe.
BonjourInterface.java

2- Définir la classe distance qui implémente l’interface (Bonjour) et hérite de la classe UnicastRemoteObject ou Activatable (utilisant elle-même les classes Socket et SocketServer, permettant la communication par protocole TCP) - dans notre cas on va s’intéresser à UnicastRemoteObject pour débuter – afin de créer un lien au système de RMI et aussi initialisation à distance d'objet. Rappelons que les objets de cette classe doivent être Serializable, un mécanisme qui permet de sérialiser des objets en flux réseau pour faciliter leur transfère.

Bonjour.java

N.B :vous remarquerez que ce cas la class Bonjour n’implémente pas la classe Serializable parce qu’elle dispose d'une propriété de type String qui est déjà Serializable.

3- Générer les classes Stub (souche) et Skeleton (squelette) en utilisant la commande : #rmic Bonjour 

4- Lancer le service d’annuaire RMI en utilisant la commande:#rmiregistryou intsancier le en ivocant la méthode createRegistry de la classe LocateRegistry puis lancer l'application serveur (Server) qui instancie l'objet distant et le publie.

Server.java

5- Créer un programme client (Client) pour accéder aux méthodes de l’objet distant.

Client.java

L’exécution du client se passe comme n’importe quel autre programme Java toutefois le cadre de notre exemple suppose que les classes suivantes soient accessibles dans le classpath.

  • Coté serveur : Bonjour.class, Bonjour_Stub.class, BonjourInterface.class et Serveur.class.
    Le bind envoie au registry une instance de type Stub d'où la nécessité de l'avoir.
  • Registry (dans le cas ou il n'est pas intégré au serveur): BonjourInterface.class,Bonjour_Stub.class.
    rmiregistry décode les objets qui lui sont passés et donc a besoin des classes et interfaces correspondantes au type des Stubs. Ce comportement est particulier à cette implantation de référence du service de registry.
  • Coté client Bonjour_Stub.class, BonjourInterface.class et Client.class.
    Ici c’est la présence des classes de Stub qui peut surprendre. Dans de nombreux cas de déploiement, comme pour les Applets, ceci ne pose aucun problème puisque c’est le serveur qui déploie le code client. Dans d’autres cas on pourra s’orienter vers un chargement dynamique des classes un concept qui n'est encore au point par rapport à CORBA si on croit les spécialistes.

Chargement dynamique.

Un client RMI peut se trouver dans une situation où il ne dispose pas de classe Stub de ce fait son exécution relèvera une exception du type ClassNotFoundException. Dans ce cas nous pouvons se tourner vers le chargement dynamique pour cela il faut:

  • Placer l'ensemble des classes du serveur dans espace web accessible par le client.
  • Mettre en place un SecurityManager(gestionnaire de sécurité) pour pouvoir charger des classes à distant soit on ajoutant cette ligne de code System.setSecurityManager(new SecurityManager())soit par option lancement de la J.V.M–Djava.security.manager cette opération implique la mise en place d'un fichier de privilèges afin de résoudre et de se connecter au hôte de registry. Ce fichier policy contenant une entrée de ce type : permission java.net.SocketPermission “host:1024-”, “connect” ;
  • Exécuter le serveur on fournissant l'URL du chargement dynamique des classes.
    java -Djava.rmi.server.codebase="http://localhost/export/ Server
  • Pour terminer exécuter le client.
    java -Djava.security.manager -Djava.security.policy=priv.policy Client

CallBack

Dans l'exemple précédant, nous avons utilisé un modèle synchrone c'est-à-dire que le client doit attendre une réponse de la part du serveur avant de pourvoir faire quoi que ce soit d'autre. Ce modèle fonctionne parfaitement mais est très restrictif, en particulier dans les situations où le traitement sur le serveur peut être relativement long.
Dans cette section nous allons étudier une technique dite "Callback" qui nous permet de construire un modèle plutôt asynchrone. Cette technique consiste à avoir une souche serveur et souche client de chaque cote et quand le client invoque une méthode distante il transmet sa référence pour que le serveur puisse le recontacter- en invoquant une méthode distant- pour lui transmettre le résultat de son appel, comme le montre le diagrame de séquance ci-dessous.

callback sequence

Comme veut la coutume on définit les deux interfaces distantes une pour chaque coté NumberGen pour le serveur et NumberAsk pour le client.
NumberGen.java

NumberAsk.java

Puis on écrit deux programmes NumberGenImpl qui représente l'implantation de l'interface distante du serveur et NumberAskImpl pour celle du client.

NumberGenImpl.java


NumberAskImpl.java

Pour tester, nous exécutons le programme serveur en premier puis le client.

Activable

Jusqu'à maintenait nous avons travaillé avec des objets qui ne sont pas nécessairement des instances situées dans un serveur actif. Parfois nous avons le désire de déclarer un objet pour l’’exportation” et ensuite arrêter la JVM et lorsqu’un client demande une référence l’objet est ressuscité au sein d’une JVM active. Pour cela nous devons travailler aves des objets particuliers autrement dit des objets "Activatable" se sont, en générale des objets distants qui héritent de la classe Activatable leur fournissant tout le support nécessaire pour qu'ils puissent être persistant.

C'est objets sont gérer par un démon système rmid qui enregistrer ces objets et les activer l' avantage est d'évite d'avoir des objets serveurs actifs en permanence même s'ils ne sont pas utilise -cela est trop coûteux en terme de ressource- aussi d’avoir des références d'objets persistantes pour qu’en cas de crash d'objet serveur le démon peut le relancer avec la même référence aussi les clients continuent à utiliser la même référence.

Un objet activable appartiens un groupe d'activation d'une part correspond à une JVM et d'autre part est chargé de surveiller, d'activer/réactiver les objets. Lors qu’un client invoque une méthode sur un objet activable, si la JVM du groupe n'est pas en cours d'exécution, elle est lancée et si l'objet n'est pas actif il est instancie avec les informations transmises lors de l'enregistrement (nom de sa classe, URL chargement bytecode de la classe dans le cas ou elle n’est pas chargeable pas CLASSPATH et les données pour le constructeur de la classe).

Activable

Pour la réalisation d'un exemple nous modifions l'implémentation du précédent objet Bonjour pour le rendre activable.(BonjourActivatable)

BonjourActivatable.java

Puis nous écrivons un programme qui permet de configurer et d'instancier l'objet activable.(InstallBonjour)

InstallBonjour.java

Nous générons le classe Stub (rmic BonjourActivatable), nous lançons le registry (rmiregistry) puis le démon rmid en lui fournissant un fichier de privilège, qui définit les autorisations nécessaire pour que ActivationGroupDescriptor puisse lancer une JVM pour un groupe d'activation:

#rmid -J-Djava.security.policy=priv.policy

Nous exécutons le programme InstallBonjour:

#java -Djava.security.policy=policy InstallBonjour "file:///c:/rmi/activale"

L'url "file:///c:/rmi/activale" permet au daemon de charger le bytecode de la classe si elle n’est pas dans CLASSPATH. Pour terminer, nous exécutons le client.

RMI et FireWall

RMI ouvre des connexions TCP directes sur des ports anonymes lorsqu'on ne les spécifie pas, alors il lui sera impossible de passer à travers des "firewalls". Pour cela il y a deux solutions envisageables :

1- La première est la solution la plus fiable, elle consiste à enregistrer l’objet en utilisant un port donné ex:
"UnicastRemoteObject.exportObject(ClientImpl,4450)" puis configurer le firewalls afin qu’il laisse passer des paquets à travers ce dernier.

2- La deuxième est plus barbare -si j'ose dire- mais utile dans le cas ou nous n'avons pas accès aux paramètres du firewall. Cette solution consiste à encapsuler les requêtes RMI dans des requêtes HTTP POST (tunneling http). Dans ce cas, nous supposons que le "firewall" bloque le trafic RMI mais laisse passer le trafic HTTP, le client doit positionner la propriété « http.proxyHost » et essaie de passer par un proxy web local et de le faire contacter le serveur à l'adresse http://localhost:4450.

RMI and Firewall

Un deuxième scénario pour cette solution s'impose. Le cas ou le client est derrière un "firewall". Dans ce cas il faudra prévoir un autre niveau de redirection  le serveur dispose d'un programme Common Getaway Interface (CGI) qui redirige la requête. Vers l'objet du serveur RMI, le client essaie de contacter le serveur à l'adresse http://localhost/cgi-bin/java-rmi?forward=4450.

RMI and Firewall

C’est une solution qui fonctionne mais des pertes de performances et des aléas de sécurité éventuelle s'opposent.  Cela dit à n'utiliser que lorsqu'on ne peut faire autrement.

Télécharger l'archive complet de ce tutoriel (RMI.zip)

Dernière mise à jour : ( 21-03-2007 )
 


Java Technology
Book Review: Head First Software Development

O'Reilly's new Head First Software Development sums up decades of research on what works and what doesn't in the often arcane world of software development.

Java Technology Headlines
 

© 2009 Le site Web de Mâamoun BERNICHI
Joomla! is Free Software released under the GNU/GPL License.