Cours 12 Contenu du cours : RMI : a quoi ca sert Comment ca marche La RMIRegistry Créer un serveur RMI La sérialisation Créer un client RMI Deploiement d’une application RMI Téléchargement des Stubs & Securite Références
Remote Method Invocation 2 A quoi ça sert ? Le RMI permet à des objets distants de communiquer par appels de méthodes. Il permet de construire des applications java distribuées , reposant sur des composants (objets) interopérables.
Remote Method Invocation 3 Les composants Une application distribuée en RMI comprend : Une (ou plusieurs) RMIregistry : Ce composant logiciel (inclus dans la jdk) agit comme un service de nommage (annuaire) entre les différents composants des applications RMI. Il maintient une structure de noms arborescente. Les objets désirant proposer leurs services (serveurs) à des clients distants s'inscrivent dans cette structure (opérations de bind-rebind). Les objets désireux d'utiliser ces services (clients) demandent à la registry de leur trouver un serveur adéquat ( opérations de lookup ). Un (ou plusieurs) serveur(s) : Un serveur propose ses services/méthodes à des objets distants, c'est dans la création des serveurs que l'effort de programmation est le plus important. Un (ou plusieurs) client(s) : Un client requiert les services (appelle les méthodes) d'un serveur distant, ces appels de méthodes sont aussi simples que s'il s'agissait de manipuler des objets locaux.
Le schéma d'utilisation typique (et le plus simple ) de RMI, Remote Method Invocation 4 Comment ça marche ? RMI registry 1-Le serveur s'enregistre auprès de la registry. 2-Le client demande à la registry un serveur. Objet Serveur Objet Client JVM B JVM A 3-Le client appelle des méthodes du serveur. Le schéma d'utilisation typique (et le plus simple ) de RMI, est basé sur ces 3 étapes.
Remote Method Invocation 5 La RMI registry (reggie) racine nomObjet1 objet1 nomRepertoire1 nomObjet2 objet2 nomObjet3 objet3 Ici, l'objet1 est associé au nom : "/nomObjet1" l'objet2 est associé au nom : "/nomRepertoire1/nomObjet2" l'objet3 est associé au nom : "/nomRepertoire1/nomObjet3" La RMI registry est une application (RMI :) )créant un processus qui écoute et accepte les connexions (par défaut, sur le port 1099), elle maintient une structure de noms hiérarchisée.
Remote Method Invocation 6 Créer un serveur Le but de l'intéropérabilité est de pouvoir exécuter les méthodes d'un objet distant. Un client n'est pas intéressé par l'implémentation propre des méthodes du serveur, c'est le coeur de la notion de services. Un serveur peut vouloir cacher son implémentation des services qu'il publie, pour des raisons de sécurité. Un serveur n'est jamais téléchargé sur le poste client. Un serveur est décrit par une interface, c'est à travers cette interface que ses méthodes sont accessibles aux clients. Interface du serveur Objet Client Objet Serveur JVM A JVM B
Remote Method Invocation 7 Créer une interface pour un serveur Le package java.rmi et les sous packages contiennent l'API RMI. Les interfaces décrivant les serveurs RMI doivent étendre java.rmi.Remote. Cette interface est un marqueur. Toutes les méthodes des interfaces de serveurs doivent déclarer une RemoteException dans leur clause Throws. Seules les méthodes décrites dans l'interface d'un serveur RMI seront accessibles à distance. Les interfaces des serveurs RMI doivent dériver de java.rmi.Remote, cette interface est un marqueur : elle ne contient ni méthode ni constante. Chaque méthode de l'interface déclare une RemoteException dans sa clause throws
Remote Method Invocation 8 Contraintes sur les méthodes distantes Les arguments et types de retour des méthodes publiées en RMI sont soumis à des contraintes , ils peuvent être : des types primitifs (ie int, long, boolean...) des objets distants (ie UnicastRemoteObject et classes filles) des objets sérialisables et c'est tout ! Les objets sérialisables sont ceux qui implémentent l'interface marqueur java.io.Serializable . Ces objets sont marqués comme étant capables de se convertir en un flux d'octets auto-decrits. A peu près toutes les classes de java sont sérialisables, même les classes de swing ! Seul un nombre restreint de classes ne sont pas sérialisables, il faut alors trouver des moyens détournés pour les transmettre sur le réseau (socket, etc..) En RMI, tous les arguments sont transmis par copie, cela signifie qu'un objet n'est pas modifié localement au retour d'un appel de méthode distant lorsqu'il est passé en argument de cette méthode.
Remote Method Invocation 9 Créer un serveur qui implémente l'interface Le package java.rmi.server contient les classes utilisées par les serveurs RMI. Chaque serveur RMI doit implémenter son interface. Chaque méthode publiée (dont le constructeur) d'un serveur RMI doit déclarer une RemoteException dans sa clause throws. Les serveurs RMI doivent dériver de java.rmi.server.UnicastRemoteObject pour hériter du comportement de serveur RMI. Les serveurs héritent de UnicastRemoteObject et implémentent leur interface. Le constructeur des serveurs RMI doit déclarer une RemoteException dans sa clause throws, tout comme chacune de ses méthodes.
Remote Method Invocation 10 Constructeur par défaut des serveurs Java.rmi.server.UnicastRemoteObject + public UnicastRemoteObject() throws RemoteException Nous devons définir un construceur qui traite l’exception Server0Impl + public Server0Impl() throws RemoteException Server0Impl Server0Impl Pas de raitement de l’exception avec le constructeur implicite Server0Impl + public Server0Impl() { super(); } Server0Impl + public Server0Impl() throws RemoteException { super(); //optionel } Server0Impl + public Server0Impl() { try { super(); } catch(Exception ex){…} } Le constructeur des serveurs RMI doit déclarer une RemoteException dans sa clause throws car la classe UnicastRemoteObject en déclare une et l’héritage nous force à redéfinir un constructeur pour traiter l’exception.
Remote Method Invocation 11 Déclarer un serveur RMI dans la RMIregistry l'objet serveur est enregistré dans la registry. On utilise la méthode rebind ou bind pour associer un objet distant à un nom dans la structure de nom de la registry. Les serveurs RMI doivent être déclarés à la RMIregistry afin de rendre publics leurs services (aux clients RMI). Pour cela, on utilise la méthode statique rebind de la classe java.rmi.Naming .
Les urls de la registry sont toutes basées sur le même schéma. Remote Method Invocation 12 Les urls de reggie Naming.Rebind(“rmi://localhost/ServeurDeZero”, obj); <protocole>://<nom d'hôte>:<port>/<chemin de l'objet> <protocole> : le protocole «rmi» est indiqué optionnellemnt <nom d'hôte> : représente le nom réseau de l'hôte hébergeant la registry du RMI. En pratique l’hôte est toujours locahost car un serveur RMI ne peut pas faire de rebind sur une registry distante pour des raisons de sécurité. <port> : représente le port de la registry, défaut à 1099. <chemin de l'objet> : représente le nom de l'objet dans la structure de noms hiérarchisée de la registry. Les urls de la registry sont toutes basées sur le même schéma. Reggie est, elle-même, un objet distribué RMI, dont les méthodes sont accessibles à des objets distants....
Remote Method Invocation 13 Le client La méthode lookup retourne un java.lang.Object qui doit donc être converti en "l'interface du serveur". (!ET PAS EN SERVEUR!) (cf acétates 16) Appel distant de méthode On utilise la méthode statique lookup de la classe java.rmi.Naming pour obtenir une instance de serveur RMI. Ensuite, les appels distants de méthodes sont aussi simples que les appels locaux.
ils passent par une classe de proxy (prestataire) Remote Method Invocation 14 14 Les Stubs (talons) et les Skeletons (squelettes) Le modèle d’application distribuée hérité de CORBA JVM A JVM B ordi Objet Client Objet Serveur réseau Appel local Appel local Stub Skel Appel distant Les clients n'appellent pas directement les méthodes du serveur distant, ils passent par une classe de proxy (prestataire) qui s'occupe de l'aspect réseau de l'appel (timeout, sérialisation, socket,etc..).
Remote Method Invocation 15 Modèle d’application distribuée de java2 3-Le client appelle des méthodes du serveur par l'intermédiaire d'un proxy : le stub du serveur. Stub Objet Client Objet Serveur JVM A JVM B Dans la plate-forme java2, il n’y a plus de Skeletons. Le Stub est le seul intervenant entre le client et le Serveur.
C’est le Stub et NON le serveur qui est renvoyé par reggie. Remote Method Invocation 16 Les Stubs Interface Serveur Renvoyé par la registry Classe Stub Classe Serveur La classe de Stub implémente l’interface du Serveur tout comme la classe du Serveur elle-même. C’est le Stub et NON le serveur qui est renvoyé par reggie.
Remote Method Invocation 17 Compilation Il faut d’abord compiler toutes les classes avec javac Génération des stubs Le nom complet de la classe à compiler avec rmic. L'option 1.2 est requise car .... Réglez le classpath comme pour javac Le stub généré par rmic. Les stubs sont des classes java générées par le compilateur RMI : rmic. rmic génère un stub pour chaque classe désirant exporter ses méthodes (UnicastRemoteObject)
Remote Method Invocation 18 Compilation Exécution windows : exemple> compileAll exemple> rmiServer Exécution linux : exemple> ./compileAll.sh exemple> ./rmicServer.sh
Remote Method Invocation 19 Exécution (1/3) RMI registry : "registry &" ou "start rmiregistry“ (sous windows) Côté serveur (tout est sur une seule ligne ) java -cp <classpath> <nom de la classe du serveur> Côté client java cp <classpath> <nom de la classe du serveur> On peut exécuter localement toutes les classes d’une application RMI. Ce mode de déploiement est trop simple et ne reflète pas la réalité.
Remote Method Invocation 20 Exécution (1/3) Exécution windows : exemple> startreggie exemple> executeServer-1 exemple> executeClient-1 Pour tuer reggie : Fermer sa fenêtre Exécution linux : exemple> ./startreggie.sh exemple> ./executeServer-1.sh exemple> ./executeClient-1.sh Pour tuer reggie, : Killall –9 rmiregistry
Remote Method Invocation 21 Critiques de l’exécution (1/3) *Le mode de déploiement proposé précédemment est trop simple. *Il ne rend pas compte de l’aspect « distribué » de l’application car le client et le serveur sont au même endroit. *De plus, le Stub du serveur doit être déployé avec le serveur. Ce qui est trop statique…et peut être évité.
Remote Method Invocation 22 Téléchargement automatique des stubs Côté serveur Lookup JVM B Objet Client RMI registry Stub Côté client JVM B Objet Serveur RMI registry bind codebase Stub Stub Stub Stub Stub Stub Stub Stub Stub Stub Stub Stub Stub Stub Stub Lorsqu’un client veut utiliser un serveur mais qu’il ne possède pas le Stub du serveur, le stub peut être télécharger automatiquement à partir du codebase donné par le serveur.
Remote Method Invocation 23 Un client sécuritaire Mise en place d’un gestionnaire de sécurité public class ClientSecure Un gestionnaire de sécurité applique une politique de sécurité. grant { permission java.net.SocketPermission "*:1024-65535", "connect,accept"; } Définition de la politique de sécurité dans un fichier texte Lorsqu’une JVM désire télécharger du code depuis une autre JVM, elle doit mettre en place une politique de sécurité. La politique de sécurité sera indiquée à la JVM avec l’option –Djava.security.policy
Remote Method Invocation 24 Exécution (2/3) Côté serveur /tmp/A/ package cours12.client package cours12.server Côté client /tmp/B/ package cours12.client security.policy.file Ce mode de déploiement va simuler deux machines différentes sur un même ordinateur. Chaque répertoire pourrait se trouver sur un ordinateur différent.
On peut exécuter localement toutes les classes d’une application RMI. Remote Method Invocation 25 Exécution (2/3) RMI registry : "registry &" ou "start rmiregistry" Côté serveur (tout est sur une seule ligne ) java -Djava.rmi.server.codebase=<URL du stub = file:/tmp/A/ > -cp <classpath> <nom de la classe du serveur> Côté client (tout est sur une seule ligne ) java -Djava.security.policy=<chemin du fichier policy> cp <classpath> <nom de la classe du serveur> On peut exécuter localement toutes les classes d’une application RMI. En placant les fichiers dans des répertoires différents, on simule deux ordinateurs.
Remote Method Invocation 26 Exécution (2/3) Exécution windows : exemple> start exemple>deploy-2 A>startReggie A> executeServer-2 A>cd ..\B B> executeClient-2 Pour tuer reggie : Fermer sa fenêtre Pour supprimer les fichiers de déploiement: exemple>deleteDeploy Exécution linux : exemple> ./deploy-2.sh exemple> cd tmp/A A> ./startreggie.sh A> ./executeServer-2.sh A> cd ../B B> ./executeClient-2.sh Pour tuer reggie, : Killall –9 rmiregistry Pour supprimer les fichiers de déploiement: exemple>./deleteDeploy.sh
Remote Method Invocation 27 Critiques de l’exécution (2/3) *L’application n’est pas encore totalement distribuée, le client et le serveur doivent être sur la même machine. *Le Stub du serveur est maintenant téléchargé dynamiquement par le client lorsqu’il se connecte à reggie. Ce qui impose au client l’utilisation d’une politique de sécurité : security.policy.file
Remote Method Invocation 28 Exécution (3/3) Côté serveur /tmp/A/ package cours12.client package cours12.server + reggie Côté client /tmp/B/ package cours12.client security.policy.file Serveur web Code téléchargeable -Soit une arborescence de classes -Soit un fichier jar Ce mode de déploiement va simuler deux machines différentes sur un même ordinateur. Chaque répertoire pourrait se trouver sur un ordinateur différent.
Remote Method Invocation 29 Exécution (3/3) RMI registry : "registry &" ou "start rmiregistry" Serveur Web : Contient le fichier http://s-java.ift.ulaval.ca/~steff/rmi-deploy.jar jar cvf rmi-deploy.jar -C <classpath> cours12/server/Server0Impl_Stub.class -C <classpath> cours12/client/Server0.class Côté serveur (tout est sur une seule ligne ) java -Djava.rmi.server.codebase=<URL du stub =URL du serveur web > -cp <classpath> <nom de la classe du serveur> Côté client (tout est sur une seule ligne ) java -Djava.security.policy=<chemin du fichier policy> cp <classpath> <nom de la classe du serveur>
Remote Method Invocation 30 Exécution (3/3) Exécution linux : exemple> ./deploy-3.sh exemple> cd tmp/A A> ./startreggie.sh A> ./executeServer-3.sh A> cd ../B B> ./executeClient-3.sh Pour tuer reggie, : Killall –9 rmiregistry Pour supprimer les fichiers de déploiement: exemple>./deleteDeploy.sh Exécution windows : exemple> start exemple> jarAll exemple>deploy-3 A>startReggie A> executeServer-3 A>cd ..\B B> executeClient-3 Pour tuer reggie : Fermer sa fenêtre Pour supprimer les fichiers de déploiement: exemple>deleteDeploy
Remote Method Invocation 31 Exécution distribuée *Modifier la classe ClientSecure afin que son URL de lookup pointe vers une autre machine qui héberge une registry et un serveur0. *Ensutie, recompilez le programme et exécuter le client de nouveau. *Notre application est désormais totalement distribuée.
Remote Method Invocation 32 Un mot sur l'organisation des fichiers et la sécurité D'une manière générale , on essaye de faire en sorte que le client ne connaisse pas directement les classes du serveur et que le serveur ne connaisse pas les classes du clients. Il est très judicieux de placer les interfaces utilisées par le client et le serveur dans un package séparé de ceux du client et du serveur. L'un des avantages de RMI sur Corba réside dans la possibilité, pour un client, de télécharger les stubs des serveurs avant de les utiliser. De la même manière, un "serveur" peut télécharger certaines classes depuis un client lorsque ces classes sont inconnues de la jvm du serveur. Cette technologie, transparente pour l'utilisateur et le programmeur, imposent des contraintes très fortes au niveau de la sécurité, puisqu'il s'agit de donner le droit à du code ”étranger" de s'exécuter sur un hôte qui ne les connait pas. Le modèle de sécurité de la jdk1.2 impose l'utilisation de fichiers "policy" définissant les permissions données à du code ”étranger" , en voici un exemple : grant { permission java.net.SocketPermission "*:1024-65535", "connect,accept"; permission java.io.FilePermission "c:\\home\\ann\\publihtml\\classes\\-", "read"; "c:\\home\\jones\\publihtml\\classes\\-", "read"; }; Les fichiers de sécurité peuvent être générés par policytool
Remote Method Invocation 33 références Un excellent tutorial de sun : http://java.sun.com/docs/books/tutorial/rmi/ Un deuxième : http://java.sun.com/j2se/1.4/docs/guide/rmi/getstart.doc.html La page de RMI : http://java.sun.com/products/jdk/rmi/ http://java.sun.com/j2se/1.4/docs/guide/rmi/index.html Téléchargement dynamique de code : http://java.sun.com/j2se/1.4/docs/guide/rmi/codebase.html Le formats des fichiers de sécurité de la jdk : http://java.sun.com/j2se/1.4/docs/guide/security/PolicyFiles.html http://java.sun.com/j2se/1.4/docs/guide/security/permissions.html Les tutoriaux et leur FAQs sont une aide précieuse pour les développeurs d'application RMI.
Remote Method Invocation 34 L’Activation des serveurs RMI Les objets serveurs RMI doivent être maintenus en vie aussi longtemps qu’un client peut les utiliser. Mais cette technique a des inconvénients : - Un serveur qui n’est utilisé que rarement doit rester en vie tout le temps et donc consommera des ressouces inutilement. - Le coût de maintenir de nombreux objets serveurs en vie peut être prohibitif en terme de ressources et dégrader considérablement les performances du serveur. Il serait bon de pouvoir activer les objets uniquement lorsqu’ils sont utilisés. Lorsqu’un objet est inutilisé, il devrait pouvoir se désactiver et ne plus consommer de ressouces C’est précisément ce que permet l’activation.
Remote Method Invocation 35 L’Activation des serveurs RMI Les acteurs de l’activation : rmid : le démon d’activation, est un logiciel qui est responsable d’activer les objets lorsqu’une demande d’invocation de méthode leur est destiné. Les groupes d’activations : sont les jvms qui vont hébergés les objets activés. L’application de démarrage : enregistre l’objet dans le framework d’activation. L’objet activable : est le serveur RMI que l’on désire activer au besoin. ( Les descripteurs d’activation : sont des classes qui contiennent toute l’information nécessaire à l’activation d’un objet.) Le framework d’activation fait intervenir plusieurs entités pour assurer l’activation des objets. Ces entités ont des rôles très distincts.
Remote Method Invocation 36 L’Activation des serveurs RMI Descripteur d’ objet activable Descripteur de groupe d’activation Enregistrement rmid Groupe d’activation Groupe d’activation Activation Objet activé Objet activé
Remote Method Invocation 37 L’Activation des serveurs RMI Il faut hériter de Activatable pour Rendre activable notre objet. Cette transformation nous oblige à définir un constructeur à deux paramètres qui appelera un des constructeurs de la classe mère. Transformer un serveur RMI en objet activable est enfantin. Il suffit de lui appliquer ces deux transformations mineures.
Les applications de démarrage suivent toujours le même schéma. Remote Method Invocation 38 Installer un gestionnaire de sécurité Créer un desc. de groupe Enregistrer le groupe Créer un desc. d’objet Enregistrer le serveur On récupère un stub que l’on peut placer dans reggie. Les applications de démarrage suivent toujours le même schéma.
Remote Method Invocation 39 Exécution de l’application de démarrage RMI registry : "registry &" ou "start rmiregistry" RMI activation daemon : “rmid –J-Djava.security.policy=<fichier policy>l &" ou "start rmid –J-Djava.security.policy=<fichier policy>" Serveur Web : Contient le fichier http://s-java.ift.ulaval.ca/~steff/activ-deploy.jar Côté serveur (tout est sur une seule ligne ) java -Djava.rmi.server.codebase=<URL du stub =URL du serveur web > -Djava.security.policy=<fichier policy> -cp <classpath> <nom de la classe du serveur> Côté client (tout est sur une seule ligne ) java -Djava.security.policy=<fichier policy> cp <classpath> <nom de la classe du serveur>
Remote Method Invocation 40 Activation-Exécution Exécution linux : exemple> ./rmicServer-2.sh exemple> ./jarAll-2.sh exemple> ./deploy-4.sh exemple> cd tmp/A A> ./startreggie.sh A> ./startrmid.sh A> ./executeServer-4.sh A> cd ../B B> ./executeClient-4.sh Exécution windows : exemple> start exemple> rmicServer-2 exemple> jarAll-2 exemple>deploy-4 A>startRmid A>startReggie A> executeServer-4 A>cd ..\B B> executeClient-4