Communication par Bus Logiciel Corba, application en C++ avec MICO
Corba
Command object request broker est une norme sur du papier, très volumineuse cette norme.
Tombée en désuétude car on préfère à l’heure actuelle les web services, mais ça permet de comprendre pas mal de choses :
Permet de faire dialoguer un client et un serveur dans des environnements hétérogènes et dans des langages objets différents.
Je vais vous montrer l’interopérabilité entre java et java
A l’heure actuelle, anciennes technologies RPC, remote procedure call, appeles de procedures, pas de procedures.
Ensuite RMI, appel de méthodes distantes : java-java
Corba, pareil qu’RMI, il y a aussi un annuaire
Ensuite RMI sur Corba, Corba était capable d’appeler des objets RMI
Puis web services
Puis client léger web app, avec serveurs d’app tomcat, glassfish, servlet et jsp
En français c’est un bus logiciel, négociateur de requetes objet. en anglais object request broker.
C’est un midleware ou intergiciel qui crée l’intetopabilité entre un client et un serveur.
Portabilité des applications entre un ORB A et un ORB. Editeur comme jacorb.
Le serveur met à disposition des objets à des clients
Le client peut être écrit dans un langage différent du serveur
Pour qu’ils puissent dialoguer il leur faut un socle commun, un langage commun, un socle IDL, interface description language.
Ca va générer des souches (stub) et des squelettes (skeleton) pour que le client et le serveur puissent discuter entre eux.
Evocation statique/dynamique des requetes
GIOP general Inter ORB protocol instancié sur TCP IP qui est devenu IIOP
Exemple d’interface IDL, langage de desription
Un objet Corba est une netité virtuelle localisée par un ORB (andresse ip numéro de port)
On associe un objet virtuel Corba à un objet du monde de la programmation.
Le client invoque la requête et ça correspond aux méthodes que l’on met
Adresse IP, avec numéro de port
Classe d’implémentation : classe qui va représenter l’objet Corba. On va faire une classe imprimante, on va instancier cette classe et on aura un objet Corba ensuite.
Le servant : instance de l’a classe d’implémentation
Architecture
La requete va traverser un squelete
Et on va loacliser l’objet Corba sur le serveur
Les sources et squelettes sont générés automatiquement à partir de la pojection de l’interfce dans un langage cible
Les fichier générés sont des fichiers ID qui vont générer le stub (client) et le sekeleton (serveur)
Application, compilation,on obtient un executable
Une question? Posez-la ici
Développer une application en C++ avec MICO
Définir le contrat en IDL : créer un fichier hotel.idl
interface Hotel {
readonly attribute long availableRooms;
boolean reserveRooms(in long rooms);
boolean cancelRooms(in long rooms);
};
On va générérer un getter et un setter, mais comme il est en lecture seule, on n’aura qu’un getter.
A la projection, on va obtenir une propriété et on aura un getter
Qualifiation du paramètre « in » : c’est renseigné AVANT l’appel de l’opération : c’est le client qui renseigne car c’est le client qui appelle.
Il y a des types : c’est projeté en types long
Une question? Posez-la ici
Compiler le fichier IDL
En C++ la projection se faisait avec la commande idl et ça générait des classes C++, souvenez vous
$ idl hotel.idl
génération de hotel.h qui contient :
class Hotel : virtual public CORBA::Object
class Hotel_stub : virtual public Hotel
class POA_Hotel : virtual public PortableServer::StaticImplementation
génération de hotel.cc
contient le code de hotel.h
La projection génère des fichiers .h et .cc dont le nom est celui du fichier IDL
Rappel :
Les deux points c’est l’héritage, la classe hérite…
J’avais une interface hotel qui génère une classe hotel, et elle sera utilisée par le client comme objet proxy. C’est l’objet proxy
Narrowing = transformer
Ensuite ca génère automatiquement le stub et le skeleton
Toujours pareil : generer une classe proxy, generer un skeleton, un stub
Pour rappel, ceux qui connaissent aussi le C++, c’est un langage procédural sur lequel on a rajouté une surcouche objet : il n’est pas tout objet de base en natif.
Une question? Posez-la ici
Implanter les interfaces IDL : créer un fichier hotel_impl.cc
#include "hotel.h" class HotelImpl : virtual public POA_Hotel { CORBA::Long theAvailableRooms(); CORBA::Long totalRooms; public : HotelImpl(CORBA::Long rooms); CORBA::Long availableRooms(); CORBA::Boolean reserveRooms(CORBA::Long rooms); CORBA::Boolean cancelRooms(CORBA::Long rooms); }; HotelImpl::HotelImpl(CORBA::Long rooms) { totalRooms = theAvailableRooms = rooms; } CORBA::Long HotelImpl::availableRooms() { return theAvailableRooms; } |
On a notre getter !
Les 2 opérations dl sont passées en méthodes, et ensuite on passe ce qu’on veut en paramètres
La classe de l’implémentation de l’interface hotel hérite du squelette
Et dans ce squelette, les opérations IDL ont été écrites en méthodes abstraites : on est donc obligé de définir ces méthodes, c’est pour ca qu’on parle d’un contrat IDL : si on ne définit pas ces méthodes, ça ne compilera pas.
Le squelette est POA_Hotel
La classe d’implémentation hérite de ce squelette qui hérite dont des méthodes abstraites.
Ces opérations IDL bon
interface Hotel { readonly attribute long availableRooms; boolean reserveRooms(in long rooms); boolean cancelRooms(in long rooms); }; |
Une question? Posez-la ici
Implanter les interfaces IDL : créer un fichier hotel_impl.cc
CORBA::Boolean HotelImpl::reserveRooms(CORBA::Long rooms) { if (rooms > theAvailableRooms) return false; theAvailableRooms -= rooms; std::cout << "reserveRooms() appelée" << std::endl; return true; }
CORBA::Boolean HotelImpl::cancelRooms(CORBA::Long rooms) { if (rooms > totalRooms) return false; theAvailableRooms += rooms; std::cout << "cancelRooms() appelée" << std::endl; return true; }
|
Une question? Posez-la ici
Implanter le serveur
A l’interieur de l’ORB, le serveur va récupérer un root POA, en résolvant une référence initiale :
#include <iostream> #include <fstream> #include "hotel.h" #include "hotel_impl.h" int main(int argc, char ** argv) { CORBA::ORB_var orb = CORBA::ORB_init(argc, argv, "mico-local-orb"); CORBA::Object_var poaobj = orb->resolve_initial_references("RootPOA"); PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(poaobj); rootPOA->the_POAManager()->activate(); HotelImpl * hotelServant = new HotelImpl(50); PortableServer::ObjectId_var id = rootPOA->activate_object(hotelServant); CORBA::Object_var hotel = rootPOA->id_to_reference(id); CORBA::String_var str = orb->object_to_string(hotel); std::ofstream os("hotel.ior"); os << str; std::cout << "Servant IOR : " << str << std::endl; os.close(); orb->run(); delete(hotelServant); orb->shutdown(true); return 0; }
|
Orb ave init
On récupère le RootPOA de cet ORB en question
On récupère une IOR qu’on tansforme en un objet dans le langage de programmation pour pouvoir utiliser le rootPOA
Activation du POAmanager
On voit « narrow » qui transforme l’objet dans le root POA dans un objet C++, on passe du monde Corba vers le monde C++
On instancie la classe d’implémentation en créant un servant, qui est un objet C++, qu’il va falloir passre dans le monde Corba, soit lui générer une identité CORBA. Pour cela, sur le rootPOA, on enregistre le servant dans le rootPOA et on récupère une IOR qui s’appelle hotel, l’identité de l’objet Corba.
Le client va prendre cet IOR et va le transformer en objet dans son langage de programmation.
Donc on a fait un objet C++, paf, puis un opjet POA.
C’est cet hotel qui représente l’IOR qui va être diffusé chez le client
Cette diffusion est faite ave ofstream, o transforme cet IOR en chaine de caracteres dans un fichier. On tranfère le fichier.
On met l’orb en écoute :
orb->run();
Une question? Posez-la ici
Implanter le client
Il a juste à faire le narrowing
Le client se connecte à l’ORB. Ensuite il récupère l’IOR dans le fichier. Ensuite il faut qu’il transforme dans un objet C++ par l’operation de narrowing :
#include <iostream> #include <fstream> #include "hotel.h"
int main(int argc, char ** argv) { CORBA::ORB_var orb = CORBA::ORB_init(argc, argv, "mico-local-orb"); std::ifstream is("hotel.ior"); char ior_text[5000]; if (is.good())is >> ior_text; else std::cerr << "Error opening " << std::endl; is.close(); CORBA::Object_var obj = orb->string_to_object(ior_text); if (CORBA::is_nil(obj)) return 1; Hotel_var theHotel = Hotel::_narrow(obj); if (CORBA::is_nil(theHotel)) return 1; if (! theHotel->reserveRooms(2)) return 1; orb->shutdown(true); return 0; } |
Une question? Posez-la ici
Le processus de compilation
$ idl hotel.idl $ mico-c++ -I. -c hotel.cc -o hotel.o $ mico-c++ -I. -c hotel_impl.cc -o hotel_impl.o $ mico-c++ -I. -c serveurHotel.cc -o serveurHotel.o $ mico-c++ -I. -c clientHotel.cc -o clientHotel.o $ mico-ld -o server serveurHotel.o hotel.o hotel_impl.o -lmico2.3.13 $ mico-ld -o client clientHotel.o hotel.o -lmico2.3.13 |
Une question? Posez-la ici
L'exécution
$ server&
[1] 20440
Servant IOR : IOR:010000000e00000049444c3a486f74656c3a312
e3000000002000000000000002c0000
00010100000a0000003132372e302e312e31001f8b140000002f323
03434302f313239393936323130352f
5f3001000000240000000100000001000000010000001400000001000
00001000100000000000901010000000000
$ client
reserveRooms() appelée
On travaille en local, avec un port 5412
IOR = créer une socket d’écoute sur l’objet distant
Une question? Posez-la ici
La commande iordump
$ iordump < hotel.ior IOR:010000000e00000049444c3a486f74656c3a312e30000 00002000000000000002c00000001010000 0a0000003132372e302e312e3100ecc4140000002f32303239362f313 239393936313838392f5f300100000024 0000000100000001000000010000001400000001000000010 00100000000000901010000000000 Repo Id: IDL:Hotel:1.0 IIOP Profile Version: 1.0 Address: inet:127.0.1.1:50412 Location: corbaloc::127.0.1.1:50412//20296/1299961889/%5f0 Key: 2f 32 30 32 39 36 2f 31 32 39 39 39 36 31 38 38 /20296/129996188 39 2f 5f 30 9/_0 Multiple Components Profile Components: Native Codesets: normal: ISO 8859-1:1987; Latin Alphabet No. 1 wide: ISO/IEC 10646-1:1993; UTF-16, UCS Transformation Format 16-bit form Key: (empty) |
En java maintenant
Une question? Posez-la ici
Définir le contrat en IDL : créer un fichier hotel.idl
On a le compilateur inclus dans le JDK, c’est le fichier idlj
Creation du fichier IDL
Compiler le fichier IDL
$ idlj -fall hotel.idl génération de Hotel.java contient une interface Hotel pour le client ie objet proxy génération de HotelHelper.java méthodes de gestion comme le narrowing Classe Narrow C’est la boite à outil génération de HotelHolder.java contient des classes wrapper pour le passage par références de paramètres génération de HotelOperations.java contient une interface HotelOperations comprenant les opérations définies dans l'IDL génération de _HotelStub.java et HotelPOA le stub et le skeleton comme le nom l'indique |
En java, pas d’héritage multiple comme C++, donc on approche par délégation.
On génère tout avec la commande « –f all »
Idlj hotel idl
En C++ on fait des passages par références, pas en Java !
On crée une classe wrapper qui encapsule pour pouvoir modifier (comme l’int)
Type Eni, type
Hotelstub.java
Mecanisme pour relier le nom de l’operation « reserved room » à la méthode méthier SUR LE SERVEUR qui contient le code
L’objet proxy hérite de la souche.
Une question? Posez-la ici
Implanter le serveur
Le serveur doit avoir un POA on récupère l’IOR tu rootPOA. Operation de narrowing qui fait appel à la classe POAHelper
import org.omg.CORBA.ORB; import org.omg.PortableServer.*; public class HotelServeur { public static void main( String [] args ) { try { ORB orb = ORB.init( args, null ); POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA")); rootpoa.the_POAManager().activate(); HotelImpl hotel = new HotelImpl(50); org.omg.CORBA.Object objref = rootpoa.servant_to_reference(hotel); String ref = orb.object_to_string(objref); System.out.println(objref); java.io.FileOutputStream file = new java.io.FileOutputStream("ObjectID"); java.io.PrintStream output = new java.io.PrintStream( file ); output.println(ref); output.close(); orb.run(); } catch ( Exception ex ) { ex.printStackTrace(); } } } |
On active le POA manager qui gère le cycle de vie du rootPOA
On instancie un servant à partir de la classe d’implémentation
On enregistre ce servant dans le rootPOA
Implanter le client
public class HotelClient { public static void main(String [] args) { org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init( args, null ); try { java.io.FileInputStream file = new java.io.FileInputStream("ObjectID"); java.io.InputStreamReader input = new java.io.InputStreamReader( file ); java.io.BufferedReader reader = new java.io.BufferedReader(input); String ref = reader.readLine(); file.close(); org.omg.CORBA.Object obj = orb.string_to_object(ref) ; Hotel hotel = HotelHelper.narrow(obj); hotel.reserveRooms(2); } catch ( java.lang.Exception ex ) { System.out.println ("Erreur");ex.printStackTrace(); } } } |
Seules sont appelables à distance les méthodes qui sont spécifiées dans l’interface IDL
Le processus de compilation
$ idlj -fall hotel.idl
$ javac HotelImpl.java
$ javac HotelServeur.java
$ javac HotelClient.java
L'exécution
$ java HotelServeur&
[1] 8395
IOR:000000000000000e49
444c3a486f74656c3a312e3
00000000000000100000000000
00082000102000000000a31323
72e302e312e3100a2bf00000031afabc
b0000000020af11784000000001000
000000000000100000008526f6f74504f
410000000008000000010000000014000
00000000002000000010000002000000000
000100010000000205010001000100
2000010109000000010001010
000000026000000020002
$ java HotelClient
reserveRooms() appelée
Causes de pannes fréquences
Si le serveur n’est pas là, j’obtiens une exception : socket error : ip, port not found
Si le fichier IOR est corrompu, le serveur régénère une IOR.
Sinon « A caractere did not map to the transission code 7 »
Une question? Posez-la ici
Des questions?