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

Cest 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?