Application de commerce électronique

Etape 2 - Application bancaire minimale

F. Boyer, S. Chassande, D. Feliot, S. Krakowiak, D. Donsez

Projet de DESS-GI option SRR  et RICM3 option SR

Année Universitaire 2001-2002

Université Joseph Fourier, Grenoble

PLAN 1. Présentation de CORBA
1.1 Clients et serveurs
1.2 IDL
1.3 Talons et squelettes
2 Application bancaire
2.1 Architecture proposée
2.2 Interface IDL proposée
2.3 Organisation logicielle proposée
3 Documentation des services utilisés


URL des services utilisés

ORBacus  : www.ooc.com
Site de l'OMG (donnant accès à la spécification IDL entres autres) : www.omg.org


Un serveur CORBA est un support permettant de rendre accessible un ensemble d'objets (écrits dans un langage de programmation quelconque) de manière distribuée. Nous allons utiliser ce support pour programmer une application bancaire qui permet à des clients ou à des organismes distants de consulter, et selon le cas de modifier des données bancaires (comptes, clients, agences, etc). Cette note pésente tout d'abord les principes d'utilisation d'un serveur CORBA, puis propose une architecture pour réaliser une application bancaire.

La norme CORBA à donné lieu à diverses implémentations, dont  ORBacus qui est celle que nous utiliserons dans le cadre de ce projet. Nous allons plus précisément utiliser la version ORBacus 4, qui implémente la spécification CORBA V2, incluant les Portable Objects Adaptors (POA).
 

1. Présentation de CORBA V2

CORBA est une norme proposée par l'OMG, pour permettre d'interconnecter des composants logiciels  (objets) écrits dans des langages de programmation divers et s'exécutant sur des machines distantes.
 

1.1 Clients et serveurs

Bien que permettant de réaliser des appels à distance sur des  objets, la norme  CORBA est basée sur un modèle client/serveur. Les objets distribués (c'est à dire, ceux que l'on souhaite rendre accessible à distance) doivent être crées et gérés par un serveur CORBA, qui a pour rôle d'exécuter les méthodes appelées par les clients sur ces objets.
N'importe quel client peut appeler une méthode sur un objet distribué, à partir du moment où il connait la référence CORBA (appelée IOR, Inter Object Reference) de cet objet. Cette référence précise à la fois quel est le serveur "chez qui" se trouve l'objet, et quel est l'objet appelé. En général, une IOR est transmise à un client soit par passage de paramètres, soit par l'utilisation d'un serveur de noms.

La figure ci-après illustre un scénario de communication entre objets distribués sur des serveurs CORBA. En (1), un client récupère l'IOR d'un objet O dans le serveur X. En (2), le client accède à l'objet O. La méthode qu'il appelle sur O crée un deuxième objet O', dont l'IOR est renvoyée au client. Ce dernier peut alors ensuite accéder à O'.

1.2 IDL

Selon la norme CORBA, les objets que l'on souhaite rendre accessible de manière répartie doivent être décrits en termes de l'interface qu'ils offrent. Le développement d'applications distribuées sur des plates-formes hétérogènes nécessite en effet une séparation stricte entre les interfaces des objets et leur implémentation. Un langage spécifique, appelé IDL (Interface Definition Language) a été défini à cet effet par l'OMG (Object Management Group). Ce langage permet de définir les interface des méthodes appelables sur un objet distribué, en termes des types des paramètres et du résultat des méthodes.

Par exemple, nous allons considérer l'interface hello définie ci-après qui permet d'afficher un message (méthode print), ainsi que de comptabiliser le nombre d'appels effectués à la méthode print. Cette interface est définie dans le module Example. Un module IDL définit une portée pour les noms d'interfaces.
 

module Example {
  interface hello;
  interface hello {
    readonly attribute long print_number;   // nombre d'affichages effectués
    void print(in string msg);                      // affichage d'un message
 } ;
} ;

Exemple de fichier IDL ( example.idl )

1.3 Talons et squelettes

Tout objet distribué possède deux représentations : une représentation client (appelée talon) et une représentation serveur (appelée squelette).
Un client possède un talon par objet distant qu'il est suceptible d'appeler. Un talon associé à un objet O a pour rôle de transfèrer les appels de méthodes effectués par le client au serveur gérant O.
De manière symétrique, un serveur possède un squelette par objet distribué qu'il gère.Un squelette associé à un objet O réceptionne les appels de méthodes sur O, et se charge d'engendrer leur exécution.
Au moment où un client effectue un appel de méthode sur un objet, l'interconnexion entre le talon et le squelette de l'objet appelé est réalisée au travers d'une couche de communication appelée Bus CORBA, ou plus généralement ORB (Object Request Broker). Le protocole de transfert des appels de méthode (définissant le format des messages échangés entre la machine cliente et la machine serveur) est appelé IIOP (Internet InterOrb Protocol).

Remarque : l'OMG spécifie en fait un protocole de communication entre ORB appelé GIOP (General Inter-ORB Protocol). Ce protocole doit être implémenté au-dessus d'une couche transport orientée connexion. IIOP est une spécialisation de GIOP utilisant TCP/IP. La spécification de GIOP est constituée de deux parties. La première est générale ; elle spécifie une représentation commune des données (CDR), le format des messages GIOP et les caractéristiques supposées de la couche de transport sous-jacente. La seconde partie, propre à IIOP, décrit la manière dont clients et serveurs CORBA établissent des connexions TCP/IP pour transmettre des messages GIOP.

La génération des classes définissant les talons et les squelettes est prise en charge par le compilateur IDL. Cette génération s'effectue à partir de l'interface IDL décrivant un objet donné, ainsi que de l'implémentation de cet objet. Autrement dit, pour tout objet distribué, le programmeur doit décrire son interface IDL, et son implémentation dans un langage supporté par CORBA (C, C++, Java, etc).

La figure ci-après récapitule ces informations. On peut voir qu'un squelette est connecté au Bus CORBA via un adaptateur d'objets (Object Adapter). Initialement, la spécification Corba version1 proposait un adaptateur d'objets basique (Basic Object Adaptator), qui était limité en terme de portabilité.  C'est la raison pour laquelle la norme Corba version 2.2 définit un nouvel adaptateur, appelé Portable Object Adaptor. Dans tous les cas, un adaptateur gère différents objets distribués dans un serveur Corba donné. C'est lui qui rend accessible ou inaccessible un objet donné, et qui invoque les méthodes appelées sur cet objet par l'intermédiaire de son squelette. Nous verrons le rôle plus précis des adaptateurs au travers de l'étape 3.

  Figure 2. Interaction entre un client et un serveur CORBA

1.4 Notion d'activation
Lorsqu'un objet distribué est créé au sein d'un serveur donné, il n'est pas immédiatement accessible à distance. Pour le rendre accessible, il faut l'activer auprès de l'un des POA du serveur courant. L'activation d'un objet distribué consiste en :


Deux modèles d'activation existent, selon que le POA auprès duquel a lieu l'activation fonctionne selon le mode implicite ou explicite. Avec le mode activation implicite, la création d'une référence distribuée (ou d'un objectId) pour un objet O auprès d'un POA entraîne automatiquement l'activation de O si celle-ci n'a pas encore été faite. Les différents moyens de créer une référence distribuée sont résumés en 1.5.

Avec le mode activation explicite, le programmeur doit explicitement activer un objet distribué auprès d'un POA. Les méthodes fournies par la classe PortableServer.POA sont :
 


Dans la terminologie Corba, l'objet qui implante une interface IDL est appelé un servant. Le type ObjectId correspont au type byte[] de Java, et son contenu n'a pas de signification particulière pour un POA. La contrainte à respecter est que deux objets distincts doivent posséder des objectId différents s'ils sont actifs au sein du même POA. Un exemple de génération d'objectId à partir d'une chaîne de caractères est donné ci-après :
 

  String anObjectId = "myObjectId";
 byte[] id = anObjectId.getBytes();

1.5 Identification d'un objet distribué et accès à cet objet
Pour accéder à un objet situé dans un serveur distant, un client doit posséder une référence distribuée vers cet objet. Une référence distribuée contient :


Une référence distribuée (type org.omg.Object) peut être construite au travers des méthodes suivantes qui peuvent être appelées autant de fois que nécessaire dans un programme. Si le POA auprès duquel est appelé l'une de ces méthodes fonctionne selon le mode implicite, et que l'objet n'a pas encore été activé, alors l'appel de la méthode provoque son activation.
 

Méthodes fournies par le servant (classe org.omg.Servant) :

// ces méthodes sont l'équivalent du connect de l'ORB Jonathan

Méthodes fournies par le POA auprès duquel l'objet est (ou doit être) activé (classe org.omg.PortablePOA) :
 

// ces methodes engendrent l'activation de l'objet si le mode du POA est implicite

Si l'on souhaite simplement connaître l'identificateur unique d'un objet sans forger une référence distribuée complète, alors la méthode suivante est disponible. Comme précédemment, si le POA auprès duquel est appelé cette méthodes fonctionne selon le mode implicite, et que l'objet n'a pas encore été activé, alors l'appel de la méthode provoque son activation.


Inversement, depuis une référence distribuée, il est possible d'obtenir l'identification unique de l'objet (objectId), ainsi que la référence Java locale de l'objet servant.
 

Méthodes fournies par le POA auprès duquel l'objet est activé (classe org.omg.PortablePOA) :


1.6 Exemple simplifié de serveur CORBA
Cette section décrit la mise en oeuvre d'un serveur Corba très simple, donnant accès à un objet distribué implémentant l'interface IDL hello définie en 1.2. En 1.4.1, nous décrivons comment compiler l'interface hello. Après la compilation des interfaces IDL d'une application, il est nécessaire de définir les implémentations de ces interfaces. Il existe deux modèles pour ce faire :
 


Selon le modèle de programmation, un servant peut donc hériter de son squelette, ou bien utiliser un délégué pour l'implémentation des méthodes. Les deux modèles sont décrits respectivement en 1.4.2 et 1.4.3. Enfin, en 1.4.4 nous expliquons comment écrire le programme du serveur qui va créer et héberger l'objet distribué, et nous donnons un exemple de client qui accède cet objet à distance.

Nous supposons dans la suite que l'organisation logicielle est la suivante :

                                                              Example
                          /                              /                           \                             \                            
                        idl                       generated                   src                        build.xml
                   (fichiers idl)           (fichiers générés)     (implémentations)

1.6.1 Compilation des interfaces IDL selon le modèle par héritage
Pour compiler cette interface, nous utilisons le compilateur IDL/Java (au travers de la commande jidl Example.idl) qui va générer les classes talon et squelette Java associées à l'interface hello. Toutes les classes générées appartiennent au package Example (nom du module). Ces classes sont les suivantes :

 

1.6.2 Ecriture d'une implémentation selon le modèle par héritage

Nous devons définir la classe helloImpl.java comme une extension de la classe helloPOA. Dans cette application très simple, la classe ExampleServer.java crée une instance de la classe helloImpl, puis crée une référence distribuée sur cet objet (méthode _this(orb)), et enfin enregistre cette référence auprès du serveur de noms. La méthode _this crée une référence distribuée en activant l'objet auprès du POA affecté par défaut au serveur courant. Ce POA (appelé RootPOA) fonctionne en effet selon le mode d'activation implicite. La classe ExampleClient.java donne un exemple de client.
Dans le modèle par héritage, le servant d'un objet distribué d'interface XXX a pour classe XXXImpl qui étend XXXPOA. Cet objet met en oeuvre à la fois l'implémentation et le squelette de l'objet.

1.6.3 Compilation des interfaces IDL selon le modèle par délégation
Pour compiler l'interface Example.idl selon le modèle par délégation, nous utilisons le compilateur IDL/Java avec l'option -tie (au travers de la commande jidl -tie Example.idl). Les classes générées comportent un fichier supplémentaire par rapport à une compilation selon le modèle par héritage : helloPOATie.java. Cette classe implémente le squelette associé aux objets d'interface hello. Ce squelette, qui doit être considéré comme servant, utilise un objet de classe helloImpl comme délégué.
Note : l'option de compilation --impl permet d'obtenir des squelettes des classes d'implémentation.

1.6.4 Ecriture d'une implémentation selon le modèle par délégation
Nous devons cette fois définir la classe helloImpl.java  comme une implémentation de l'interface helloOperations. Dans la classe ExampleServer.java,  il faut d'abord instancier la classe helloImpl, puis créer un servant en instanciant la classe helloPOATie et en lui passant, comme paramètre de construction, une référence vers la classe d'implémentation.
 

helloImpl hello = new helloImpl();
helloPOATie helloTie = new helloPOATie(hello);


L'activation de l'objet crée peut être réalisée par son créateur (classe ExampleServer), ou bien par lui-même, selon les choix de programmation que l'on réalise. Dans le premier cas, le créateur n'a qu'à appeler la méthode activate_object(helloTie) sur le POA choisi. Dans le second cas, c'est dans la classe helloImpl que l'on souhaite effectuer cette activation. La classe ExampleClient.java donne un exemple de client.

1.6.5 Lancement de l'application
 Pour exécuter l'application, il faut effectuer les commandes suivantes qui vous sont fournies dans le fichier ant build.xml:
 


java -cp <classpath> com.ooc.CosNaming.Server --ior > Naming.ref &
 


java -cp <classpath> Example.ExampleServer -OAport 2200 -ORBnaming `cat Naming.ref` &
 


java -cp <classpath> Example.ExampleClient -OAport 2000 -ORBnaming `cat Naming.ref` &

2. Application bancaire

Cette section propose une architecture pour la réalisation de l'application bancaire en termes de serveurs CORBA. Bien entendu, il est tout à fait possible d'étendre ou de modifier cette architecture.

2.1 Architecture proposée

Nous proposons qu'une application bancaire soit mise en oeuvre par trois types de serveurs CORBA :


Le schéma ci-dessous montre l'enchaînement des opérations pour obtenir la référence d'une agence.


Cette dernière opération crée automatiquement un talon correspondant à un objet Agency sur le site client. Ce dernier peut donc par la suite appeler les méthodes de l'interface Agency sur l'objet correspondant.

2.2 Interfaces IDL proposées

Les banques doivent fournir un ensemble de services spécifiés par des interfaces IDL. Nous proposons les interfaces IDL suivantes (fichier bankServices.idl, sous ${GICOM}/Java/Bank), qui peuvent bien entendu être modifiées et/ou complétées par vos soins. L'accès initial à une banque étant donné son nom sera réalisé au travers du serveur de noms fourni par ORBacus.

Les méthodes registerAgency et removeAgency permettent respectivement d'enregistrer et de retirer une agence d'une banque donnée. La référence d'une agence rattachée à une banque peut être récupérée par la méthode getAgency. La méthode getAgenciesList permet de récupérer les références de toutes les agences rattachées à une banque donnée.

A partir d'un objet Agence, on doit pouvoir enregistrer ou retirer des clients, et récupérer leur référence distribuée. Les objets Clients sont donc également accessibles au travers d'une interface IDL.

A partir d'un objet Client, on peut récupérer des informations (nom, adresse, etc) sur le client, et l'on peut également créer, consulter ou détruire des comptes pour ce client, ainsi que récupérer leur référence.

Les objets  Account devront principalement permettre de consulter ou de modifier un solde.

2.3 Organisation logicielle proposée

L'organisation logicielle recommendée pour conserver une structuration claire des programmes ainsi que des talons et des squelettes générés lors de la compilation des interfaces IDL est la suivante.

                         GICOM
                               |
                           Java
                               |
                           Bank /                        /               |                 \                 \                       \ bankServices.idl        bankServices    classes       src            applet            Naming.ref

 

3 Utilisation des services supports

URL Java: http://java.sun.com/products/jdk/1.2/docs/api/index.html
URL ORBacus 3.0 (Société : Oriented Object Concepts (USA))  : www.ooc.com

Votre environnement doit être configuré comme suit  (cf. fichier CONFIGENV):


- accès aux binaires du jdk1.2 (/usr/Solaris_JDK_1.2.1_03/bin sur les Tx)
- accès aux binaires d'ORBacus (${GICOM_ENS}/ORBacus/bin sur les Tx)


OB.jar,OBBiDir.jar,OBEvent.jar,OBIMR.jar,OBNaming.jar,
OBProperty.jar,OBTest.jar,OBTime.jar,OBTrading.jar,OBUtil.jar


L'appletviewer se trouve dans ${JAVA_HOME}/bin. Le lancer par la commande appletviewer.

ORBacus for C++ and Java (Mark Laukien, Uwe Seimet, Matthew Newhook, Mark Spruiell)

             Manuels de référence de l'ORB développé par Object Oriented Concepts.

          Au coeur de Corba (Jérôme Daniel), Editions Vuibert, Paris, 2000.

Contact : informatique@vuibert.fr

www.omg.org  (Site de l'OMG)

www.objectweb.org (Un ORB Java fourni en Open Source)

www.inf.fu-berlin.de/~brose/jacorb (Jacorb est un ORB écrit en Java)

www.cs.wustl.edu/~schmidt/ (L'ORB TAO est disponible sur ce site)