CORBA, une introduction par l'exemple

Sylvain BARTHELEMY, (barth@tac-financial.com)
www.sylbarth.com

Introduction

L'informatique répartie est un des enjeux principaux de l'informatique actuelle et à venir. De l'architecture de terminaux centralisée qui servait encore de modèle il y a peu de temps, nous somme passé à l'architecture client/serveur. L'information est maintenant répartie entre différents serveurs du système et non plus centralisée sur un seul et même serveur : elle est répartie et distribuée aux clients de façon transparente. L'information distribuée, voilà donc le maître mot. Le world wide web, qui nous est si familier, est un exemple réussi d'application distribuée. Les clients, par l'intermédiaire d'un navigateur, se connectent à des serveurs sur lesquels des pages web nous sont proposées (le plus souvent encore statiques). Cependant, rien ne vous empêche de proposer vous aussi de l'information ou même d'installer votre serveur (sauf peut être l'InterNIC...), vous êtes alors client... mais aussi serveur : le web se sont des clients mutliples mais aussi des serveurs mutliples.

La norme CORBA

CORBA ou Common Object Request Broker Architecture est né dans les année 1990 du besoin de faire communiquer ensemble des applications en environnement hétérogène (plusieurs systèmes et plusieurs langages). CORBA n'est qu'un sous ensemble du projet ODP-RM ou Open Distributed Processing Référence Model vise à mettre en place une norme d'architectures distribuées ouvertes. L' Object Management Group, créé en 1989 et regroupant plus de 750 membres (vendeurs de logiciels, développeurs et utilisateurs), collabore avec l'ODP pour la mise en place d'une norme sur le middleware, et a créé à cet effet la norme CORBA.

CORBA est donc une norme et rien ne contraint l'implémentation les développeurs de produits CORBA. Ils ont le libre choix de l'implémentation. La popularité de l'Internet à ensuite amené les concepteurs de la norme CORBA à définir un protocole de communication entre les objets adapté à Internet. Ce protocole s'appelle IIOP, pour Internet Inter-ORB Protocol. Sommairement, l'Object Management Architecture Guide défini :

  1. CORBA : cadre visible que doivent respecter les développeurs de bus CORBA;
  2. CORBA Services : les services objet communs (Common Object Services) proposent des outils pour faciliter l'utilisation courante des objets CORBA. Les services sont constituté des interfaces suivantes (CORBA 2.2 / 98-10-53)
    1. Naming
    2. Event
    3. Persistent Object
    4. Life Cycle
    5. Concurrency Control
    6. Externalization
    7. Relationship
    8. Transaction
    9. Query
    10. Licensing
    11. Property
    12. Time
    13. Security
    14. Object Trader
    15. Object Collections
  3. CORBA Facilities : les utilitaires communs définissent un cadre de haut niveau pour la création de logiciels à l'aide de composants réutilisables. Ils sont à ce jour bien moins avancés que les services. Les domaines concernés par les utilitaires sont :
    1. la gestion des tâches
    2. l'interface utilisateur
    3. la gestion de l'information
    4. l'administration système
  4. Domain Interfaces : les interfaces de domaines concernent des marchés verticaux et définissent donc des interfaces spécialisée répondant aux besoins spécifiques de tel ou tel marché comme les télécommunications ou la finance par exemple.

A l'heure ou j'écris ces lignes, la norme CORBA en est à sa version 2.2 mais on parle déjà de la version 3. Si CORBA constitue la première initiative majeure dans le domaine des objets distribués, quelques alternatives sont aujourd'hui possibles. Ainsi, il m'a semblé important ici de noter quelques différences entre CORBA et d'autres solutions proposées pour l'informatique répartie et les objets distribués : RPC et RMI et DCOM. Le cas de RMI ou Remote Method Invocation ne concerne que les dialogues Java/Java et donc se différencie de Java par le fait que cette méthode est attachée à un langage particulier. RPC ou Remote Procedure Call permet comme son nom l'indique d'invoquer des procédures distantes mais se trouve mal adapté aux dialogues d'objets distants. Enfin, le cas de DCOM est plus complexe car DCOM est l'alternative CORBA proposée par Microsoft. Si CORBA défini une norme, DCOM défini aussi son implémentation et se limitait jusque récemment à l'interface Windows. De très bonnes études sont disponibles sur le Web au sujet de la comparaison des deux systèmes. Ayant personnellement pratiqué les deux, CORBA me parait beaucoup plus simple et pratique d'utilisation.

Le langage de définition d'interfaces : IDL

A la base de CORBA, est défini l'IDL ou Interface Definition Language. Il permet de définir dans un langage commun à l'ensemble des compilateurs, la partie visible d'un objet : méthodes et propriétés. Le principe utilisé ici est la séparation de l'interface d'une objet et de son implémentation.

A titre d'exemple, le listing suivant. Présente l'interface IDL d'un service minimal de gestion du compte d'un client (cet exemple est l'équivalent CORBA du fameux hello.c,hello.java, hello.pl...) :

    // CompteClient.idl
    interface CompteClient {
         void credit ( in unsigned long montantFRF );
         void debit  ( in unsigned long montantFRF );
         long solde  ( );
    };

Au premier coup d'oeil, les développeurs familiers de C++ auront sans doute remarqué certaines ressemblances entre ce dernier et IDL. Peut importe l'implémentation de l'interface CompteClient du moment qu'elle répond à l'interface spécifiée. IDL génère une souche (stub) pour le client et un squelette (skeleton) pour le serveur.

Avec MICO cette opération est effectuée simplement par la commande :

    idl CompteClient.idl

qui génère les classes C++ requises dans le fichier CompteClient.cc.

Le bus d'objets de CORBA

Le coeur de CORBA est constitué par l'ORB qui est le conduit/bus par lequel les requêtes sur les objets transitent. L'Object Request Broker ou ORB n'est pas directement accessible au programmeur d'applications CORBA qui n'utilise qu'une référence.L'ORB gère les transferts entre les clients et les serveurs. L'adaptateur d'objets, est quand à lui chargé de la gestion des références aux objets et de l'activation des implémentations : l'adaptateur d'objets est donc, comme son nom l'indique, le " canal " par lequel l'ORB est connectée à l'implémentation de l'objet. Différents types d'adaptateur d'objets peuvent être implémenté mais la norme CORBA 2.0 ne requière que le BOA ou Basic Object Adapter.

Ainsi, à l'aide d'un compilateur idl et de vos fichiers idl (présenté dans la section précédente), vous générez des souches pour les clients et des squelettes pour les serveurs. Vous n'avez qu'à programmer l'implémentation de votre classe serveur (ici une classe est assimilée à une classe C++) qui doit hériter du squelette généré par idl. Une fois vos programmes clients et serveurs compilés, vous pourez lancer votre serveur et l'ORB fera tout le travail de pliage/dépliage des requêtes des clients sur les objets locaux et distants à vôtre place. Pour plus de clarté un schéma explicatif du bus CORBA est donné ci-dessous.

De nombreuses implémentations du bus CORBA existent à ce jour et beaucoup sont commerciales. Cependant, quelques produits gratuits on vu le jour récemment et certains sont utilisables au même titre que des bus commerciaux pour la conception d'applications robustes et fiables. MICO (Mico Is COrba) est une implémentation libre mais de très bonne facture de la norme CORBA 2.0 (sous licence GPL). Les possibilités offertes par ce logiciel rivalisent sans problème avec les ténors en version commerciale. De plus MICO se compile sur une grande variété de plateformes : Linux, DEC Alpha et même sous Windows NT. Cependant, même s'il fonctionne sous Win95/98 il requiert NT et les GNU Tools pour la compilation. Nous avons donc choisi ce produit pour l'exemple présenté dans la section suivante qui pourrait cependant facilement se compiler à l'aide d'un autre bus.

Exemple de mini application

Afin d'illustrer les concepts d'ORB et de BOA nous présentons le code d'un serveur CORBA (avec nommage) associé à l'interface CompteClient :

    // serveur.cc
    #include "mico/naming.h"
    #include "CompteClient.h"

    // --- implémentation
    class CompteClient_impl : virtual public CompteClient_skel {
        CORBA::Long _solde;
    public:
        CompteClient_impl () { _solde = 0; }
        void credit( CORBA::ULong montantFRF ) { _solde += montantFRF; }
        void debit ( CORBA::ULong montantFRF ) { _solde -= montantFRF; }
        CORBA::Long solde() 	               { return _solde; }
    };

    // --- lancement du serveur
    int main(int argc, char* argv[])
    {
    // --- initialisation du bus et de l'adaptateur d'objets
    CORBA::ORB_var orb = CORBA::ORB_init ( argc, argv, "mico-local-orb" );
    CORBA::BOA_bar boa = CORBA::BOA_init ( argc, argv, "mico-local-boa" );

    // --- création de l'objet
    CompteClient* cc = new CompteClient_impl;

    // --- connexion au service de nommage
    CORBA::Object_var            ns = orb->resolve_initial_references ("NameService");
    CosNaming::NamingContext_var nc = CosNaming::NamingContext::_narrow (ns);

    // --- définition du chemin d'accès
    CosNaming::Name name;
    name.length (1);
    name[0].id   = CORBA::string_dup ("MonCompte");
    name[0].kind = CORBA::string_dup ("");

    // --- enregistrement de l'objet
    nc->bind (name, cc);

    // --- serveur ok
    boa->impl_is_ready (CORBA::ImplementationDef::_nil());
    orb->run ();

    // --- fin...
    CORBA::release(cc);
    return 0;
    }

Le client n'implémente pas d'objet et n'a donc pas besoin du BOA

    // client.cc
    #include "iostream.h"
    #include "mico/naming.h"
    #include "CompteClient.h"

    int main(int argc, char* argv[])
    {
    // --- initialisation du bus et de l'adaptateur d'objets
    CORBA::ORB_var orb = CORBA::ORB_init ( argc, argv, "mico-local-orb" );

    // --- connexion au service de nommage
    CORBA::Object_var            ns = orb->resolve_initial_references ("NameService");
    CosNaming::NamingContext_var nc = CosNaming::NamingContext::_narrow (ns);

    // --- définition du chemin d'accès
    CosNaming::Name name;
    name.length (1);
    name[0].id   = CORBA::string_dup ("MonCompte");
    name[0].kind = CORBA::string_dup ("");

    // --- résolution du nom pour obtenir une référence sur MonCompte
    CORBA::Object_var obj    = nc->resolve (name);
    CompteClient_var  compte = CompteClient::_narrow( obj );

    // --- quelques opérations sur mon compte...
    compte->credit(1000000);
    cout << "solde: " << compte->solde() << endl;
    // --- ... super !

    return 0;
    }

Quelques implémentations de CORBA

Les implémentations de la spécification du bus CORBA sont majoritairement commerciales. Cependant, les produits gratuits sont de plus en plus performants et MICO est un bon exemple de produit gratuit et puissant.

VisiBroker 4 commercial CORBA2.3 / c'est un produit commercial mais de très bonne facture. Utiliser CORBA sous Windows devient presque facile... un must !
MICO gratuit CORBA2 / c'est un produit de très bonne qualité qui peut rivaliser avec des bus commerciaux.
Robin gratuit CORBA2 / freeware de bonne qualité implémenté en Java.
Orbacus gratuit pour une utilisation non commerciale. CORBA2
OmniORB2 gratuit. CORBA2
Xerox ILU gratuit Outil très puissant mais plus complexe à utiliser que les précédents et qui fait partie du projet Inter-Language Unification de Xerox.
CORBAScript gratuit Ce language interprété permet l'utilisation d'objets CORBA par simples scripts (de la même manière que l'on utilise les objets automation avec Perl pour prendre un exemple concret).

Bibliographie

Je remerçie les auteurs cités dans la bibliographie pour leurs ouvrages dans lesquels j'ai largement puisé pour écrire cette note.


www.sylbarth.com