Lods RMI RMI (Remote Method Invocation) est une API fournissant une approche de haut niveau de la programmation distribuée. On peut ainsi invoquer des méthodes d'un objet distant (résidant sur un serveur) de la même manière que l'on appelle les méthodes d'un objet local. Cette API est présente dans le JDK standard depuis la version 1.1 et a été améliorée dans la version 1.2. Développé pour permettre l’appel de méthodes entre objets Java s’exécutant dans des VM différentes. Si cette API est simple à mettre en oeuvre pour le développeur, elle implique que le serveur (dans lequel résident les objets distribués) et les clients soient écrits en Java. Cette situation est cependant maintenant assez commune pour que la mise en oeuvre de RMI soit envisageable. Si ce n'est pas le cas, on préférera se tourner vers une solution qui puisse être implémentée dans d'autres langages, comme CORBA. Stub et Skeleton Stub ==> Client applet et l’interface Skeleton ==> Serveur driver InterClient pour se connecter à la B.D. et l’interface et son implémentation Connaissance Java : Pour concevoir une application RMI, il faut connaître les principaux mécanismes, instanciation et utilisation des objets. Pour qu’un objet puisse être utilisé en RMI, il faut qu’il soit sérialisable, c’est-à-dire implémenter l’interface java.io.Serializable. Dans les cas complexes, on doit coder les méthodes readObjects et writeObject, pour permettre un transport plus approprié. Interface : Dans un premier temps on doit savoir la ou les méthodes que l’on veut distribuées. Comme le client doit aussi connaître ces méthodes pour pouvoir les appeler, on crée une interface qui va être partagée entre le client et le serveur. Ce dernier implémentant cette interface. Exemple : import java.rmi.Remote; import java.rmi.RemoteException; public interface JCustomer extends Remote { public String getCustomerName(String customerID) throws RemoteException; } Lods Le serveur met à disposition des clients la méthode leur permettant la recherche du nom Note : Objet Integer et non int ->int n’est pas un objet et donc pas sérialisable !!!! La méthode rebind permet de faire connaître le serveur au système d’enregistrement et de sécurité Stub et Skeleton Pour que le client puisse utiliser l’objet distribué, il faut créer un petit bout de code permettant le lien entre l’interface et l’objet distant. Lorsque le serveur crée un objet distribué, il ne fait pas vraiment de connexion direct avec ses clients, il utilise un autre serveur qui lui est sécurisé (enfin presque) Pour que le serveur puisse effectuer le lien entre l’objet distribué et l’enregistreur de serveur, il faut une classe, c’est le rôle de la classe …_Skel.class Le transport des appels est géré par RMI à travers un couple de programmes jouant le rôle d’adaptateurs -> Stub / Skeleton. En fait lorsqu’un client effectue un appel à l’objet distant, il réalise un appel classique dans le code du stub, ce dernier intégrant tout le code nécessaire au transport de l’appel vers le serveur. Le Skeleton, quant à lui, définit l’infrastructure nécessaire à la prise en charge des appels côté serveur. Stub et Skeleton : réalisent les appels sur la couche réseau et se chargent de l’empaquetage et du dépaquetage des paramètres des méthodes (marshalling et démarshalling) Avant de pouvoir effectuer un appel de méthode sur un objet RMI, le client devra obtenir une référence initiale. Vous obtiendrez généralement cette référence à travers l’annuaire RMI L’attachement d’un client à un objet RMI s’effectuera à l’aide d’une adresse au format suivant : Rmi://NomServeur/NomDeLObjetRmi La sérialisation : RMI utilise la sérialisation afin de transporter les références d’objets entre clients et serveurs. La sérialisation est un mécanisme Java permettant la persistance des objets. Un objet est sérialisé lorsque son état est sauvegardé vers un dispositif de stockage quelconque et désérialisé par une opération de relecture de l’objet dans un flux et construction de l’instance mémoire correspondante. java.io.Serializable Page 686 Lods [Mes prises de notes Middleware -> P. 680 -> tolérance panne -> équilibrage machine RMI -> 100 % JAVA -> différent avec CORBA utilise plusieurs langages RMI utilise directement les sockets Objet serveur | interface | objets client Lire le tutorial sur streamable dataSet] RMI ou Remote Method Invocation permet de créer des applications java-à-java distribuées, dans lesquelles les méthodes des objets java distants peuvent être appelées depuis des machines virtuelles java et sur différents hôtes. Un programme java peut effectuer un appel sur un objet distant lorsqu’il obtient la référence de l’objet distant, soit en recherchant l’objet distant dans le service d’annuaire d’amorce fourni par RMI, soit n recevant la référence sous forme d’argument ou de valeur de retour. RMI utilise la sérialisation d’objets pour le marshalling et le dé-marshalling des paramètres, il ne tronque pas les types, et supporte un véritable polymorphisme orienté objet. Dans le langage de programmation Java un objet distant est une instance d’une classe qui implémente une interface distante. Votre interface distante déclarera chacune des méthodes que vous souhaitez appeler à distance. Les interfaces distantes ont les caractéristiques suivantes : - L’interface distante doit être déclarée publique -> sinon les clients provoque une erreur lorsqu’ils tentent de charger un objet distant implémentant l’interface distante. - L’interface distante étend l’interface java.rmi.Remote - Chaque méthode dit déclarer java.rmi.RemoteException (ou une superclasse de RemoteException) dans sa clause throws, en plus des exceptions propres à l’application - Le type de données de tout objet distant transmis sous forme d’argument ou de valeurs de retour doit être déclaré en tant que type interface distante et non en tant que classe d’implémentation. Comme l’invocation des méthodes distantes peut échouer de manière très différente de l’invocation des méthodes locales, les méthodes distantes signalent les échecs de communication en déclenchant une exception java.rmi.RemoteException Au minimum, la classe d’implémentation d’un objet distant doit : - Implémenter une interface distante Définir le constructeur de l’objet distant Lods - Fournir des implémentations pour les méthodes pouvant être appelées à distance. Dans ce contexte, une classe « serveur » est une classe ayant une méthode main qui crée une instance de l’implémentation de l’objet distant , et qui lie cette instance à un nom dans le registre RMI. - créer et installer un gestionnaire de sécurité Créer une ou plusieurs instances d’un objet distant Recenser l’objet distant Implémenter une interface distante : Dans le langage Java, lorsqu’une classe déclare qu’elle implémente une interface, un contrat est passé entre la classe et le compilateur. Parc e contrat, la classe garantit qu’elle fournira le corps des méthodes, ou définition, pour chacune des signatures des méthodes déclarées dans l’interface qu’elle implémente. Les méthode d’interface sont implicitement public et abstract, ainsi si la classe d’implémentation ne remplit pas son contrat, elle devient par définition une classe abstraite et le compilateur signalera ce point si la classe n’a pas été déclarée abstract. Lorsqu’un objet RMI publie une interface, il définit les signatures d’un ensemble de méthodes et seules ces méthodes sont accessibles par le client. La classe d’implémentation déclare la ou les interfaces distantes qu’elle implémente public class HelloImpl extends UnicastRemoteObject implements Hello { Le constructeur d’une classe distante procure les mêmes fonctionnalités que le constructeur d’une classe non distante : il initialise les variables de chaque nouvelle instance de la classe et renvoie une instance de la classe au programme ayant appelé le constructeur. En outre, votre instante d’objet distant a besoin d’être « exportée ». Exporter un objet distant le rend capable d’accepter les demandes entrantes des méthodes distantes en écoutant s’il existe des appels entrant pour l’objet distant sur un port anonyme. Lorsque vous étendez java.rmi.UnicastReloteObject ou java.rmi.activation.Activable, votre classe sera automatiquement exportée à la création. public HelloImpl(String s) throws RemoteException { super(); } Lods comme l’exportation de l’objet peut déclencher une excepttion java.rmi.RemoteException, vous devez définir un constructeur qui déclenche une RemoteException, même s’il ne fait rien d’autre. EN RESUME : La classe d’implémentation d’un objet distant doit : - Implémenter une interface distante Exporter l’objet afin qu’il puisse accepter les appels entrants aux méthodes distantes Déclarer son ou ses constructeurs pour, au moins, déclencher une java.rmi.RemoteException L’appel de la méthode super() ; invoque un constructeur sans argument de java.rmi.unicastRemoteObject, qui exporte l’objet distant. Fournir une implémentation pour chaque méthode distante L’implémentation de classe d’un objet distant contient le code qui implémente chaque méthode spécifiée dans l’interface distante. Les objets distants sont transmis par référence. La référence à un objet distant est en fait une référence à un Stub, qui est un Proxy côté client pour l’objet distant La méthode main du serveur doit d’abord créer et installer un gestionnaire de sécurité : le RMISecurityManager : If (System.getSecurityManager() == null) { System.setSecurityManager(new RMISecurityManager()); } Un gestionnaire de sécurité doit être exécuté pour garantir que les classes chargées n’effectuent pas d’opérations non autorisées. Si aucun gestionnaire de sécurité n’est spécifié aucun chargement de classe par les clients et serveurs RMI n’est autorisé Créer une ou plusieurs instances d’un objet distant La méthode main du serveur doit créer une ou plusieurs instances de l’implémentation de l’objet distant qui fournit le service. HelloImpl obj = new HelloImpl() ; Lods Le constructeur exporte l’objet distant, ce qui signifie qu’une fois crée, l’objet distant est prêt à accepter les appels entrants. Recensement de l’objet distant Pour qu’un appelant (un client, un pair ou une applet) soit en mesure d’appeler une méthode sur un objet distant, il doit d’abord obtenir la référence de l’objet distant. RMI fournit un registre d’objet distant qui vous permet de lier un nom de type url sous la forme //host/nom_d’objet à l’objet distant, où nom_d’objet est un nom de chaîne. Le registre RMI est un simple serveur de noms côté serveur qui permet aux clients distants d’obtenir la référence à un objet distant. Par exemple : le code suivant lie le nom « HelloServer » à une référence de l’objet distant Naming.rebind(« //localhost/HelloServer »,obj) ; Le premier paramètre est une java.lang.String de format URL, représentant l’emplacement et le nom de l’objet distant Le second paramètre est la référence à l’implémentation de l’objet sur laquelle les méthodes distantes seront appelées Le runtime de RMI remplace une référence au stub de l’objet distant par la référence de l’objet distant spécifié par l’argument obj. Obtient la référence à l’implémentation de l’objet distant (« HelloServer ») depuis le registre RMI de l’hôte serveur. Comme la méthode Naming.rebind, la méthode Naming.lookup utilise une java.lang.string au format URL. Naming.lookup prend en charge les tâches suivantes : - construit une instance du stub registre (pour contacter le registre du serveur) en utilisant le nom d’hôte et le numéro de port fournis en arguments de Naming.lookup - Utilise le stub registre pour appeler la méthode lookup sur le registre, en utilisant le composant nom de l’URL (« HelloServer ») o Le registre renvoie l’instance HelloImpl_Stub liée à ce nom o Reçoit l’instance du stub de l’implémentation de l’objet distant (HelloImpl) et charge la classe stub -> CLASSPATH - Naming.lookup renvoie le stub à son appelant (HelloApplet) Lods L’applet invoque la méthode sayHello distante sur l’objet distant du serveur. - RMI sérialise et renvoie la chaîne « Hello World » RMI désérialise la chaîne et la stocke dans une variable appelée message La chaîne URL construite passée en paramètre à la méthode Naming.lookup doit inclure le nom d’hôte du serveur. Sinon c’est le client qui est utilisé par défaut et provoque des problèmes avec le gestionnaire de sécurité. Création du fichier policy.txt Compilation des fichiers sources .java -> pour créer des fichiers .class ainsi que des stubs et des squelettes. Un stub est le Proxy côté client d’un objet distant, qui fait suivre les appels RMI au répartiteur (squelette) côté serveur, qui fait suivre à son tour l’appel à l’implémentation de l’objet distant. Applications RMI sont souvent compris en 2 programmes séparés -> serveur / client. Un serveur qui crée les objets distants et qui les rends accessibles par référence et attend que les clients invoquent les méthodes de ses objets distants. Un client -> obtient référence objet distant du serveur ou plusieurs et invoque les méthodes utilisé le rmiregistry pour obtenir les références aux objets distants Le serveur -> main -> crée instance objet distant -> implémente l’interface -> crée le gestionnaire de sécurité et fini avec un petit Naming.bin (« … »,obj) référence -> référence d’un objet distant est un stub dans le côté client avant qu’un client puisse invoquer une méthode sur un objet distant, il doit d’abord obtenir une référence à cette objet distant -> RMIRegistry -> serveur de nom -> permet au client de recevoir une référence à l’objet distant. Constructeur -> super() ; -> aller dans le truc unicast -> écoute des appels des clients /// Le client utilise la méthode Naming.lookup -> pour chercher l’objet distant avec la référence dans le registre de l’hôte distant vers le RMIRegistry -> récupérer la référence et pouvoir faire des appels sur le serveur Lods Résolution de L’exercice Inspiré du cours -> http://flenu.ise-mons.be/jbuilder6/pdf/database.pdf