deniger
2002-10-12
Présentation des premières étapes à suivre pour intégrer un code de calcul dans un environnement objet distribué.

dodicoIntégration d'un code de calcul

Dans ce document, nous supposerons que le code concerné se nomme Exemple. Il s'agit de définir et d'implanter les interfaces de communication de ce code. A la fin de ce document, il sera possible de lancer le code de calcul exemple à distance (grâce à IDL/CORBA) et à partir de code java. Lors de la création de votre projet, vous devez suivre les spécifications de dodico

Etape 1: l'exécutable

Dans un premier temps, il faut s'assurer que le code s'exécute correctement sous tous les systèmes d'exploitation ( Windows, Unix/Linux,...). Dans la plupart des cas, il faut créer des scripts de lancement afin de pouvoir exécuter le code à partir d'une ligne de commande. Le code de calcul vag peut être utilisé comme exemple.

Les exécutables et les scripts de lancement seront disposés dans le dossier dodico_serveurs/exemple. Si la licence le permet, les sources peuvent être ajoutées au dossier dodico_serveurs/src/exemple/.

Etape 2: L'interface idl

Le fichier IDL

Il s'agit maintenant de créer les interfaces et les structures de communication du code. Elles seront définies dans le module exemple du fichier dodico_idl/code/exemple.idl ( un fichier IDL est proposé ci-dessous). Les structures doivent suivre le plus fidèlement possible l'architecture des fichiers d'entrée-sortie du code. Les signatures des 3 interfaces (IParametresExemple, ICalculExemple et IResultatsExemple) doivent être respectées.

/* * @file         exemple.idl * @creation     2002-07-21 * @modification $Date: 2004/05/05 12:36:03 $ * @license      GNU General Public License 2 * @copyright    (c)1998-2001 CETMEF 2 bd Gambetta F-60231 Compiegne * @mail         devel@fudaa.org */
Les commentaires du fichiers ( cf la spécification nommage de dodico)
#ifndef _EXEMPLE_IDL
#define _EXEMPLE_IDL
Les commandes C qui vérifient si la variable _EXEMPLE_IDL est déjà définie.
#include "general/calcul.idl"
Le fichier calcul.idl est nécessaire : il définit les 3 interfaces de base (IParametres, ICalcul et IResultats) qui sont dérivées par toutes les interfaces des codes de calcul.
/** * Un exemple .... * @version      $Id: integration.xml,v 1.2 2004/05/05 12:36:03 deniger Exp $ * @author       Fred Deniger */
Les commentaires du module exemple.
module exemple
{
Le début du module
 struct SParametres
 {
  chaine nom;
  temps t;
  ...
 };

 struct SParametres02
 {
  ...
 };
Définition des structures des paramètres.
 struct SResultats
 {
  ...
 };
Définition d'une structure pour les résultats.
 interface IParametresExemple : ::calcul::IParametres
 {
  attribute SParametres parametres;
  attribute SParametres02 parametres02;
 };
L'interface des Paramètres. Le mot-clef attribute est un raccourci pour définir deux méthodes d'accès. La ligne:
  attribute SParametres parametres;

est équivalente à:

  SParametres parametres();
  rien parametres(in SParametres params);

L'interface mère (calcul::IParametres) ne définit aucune méthode : elle a un rôle de typage uniquement.
 interface IResultatsExemple : ::calcul::IResultats
 {
  SResultats resultats();
 };
L'interface des Paramètres. Elle définit uniquement un accesseur aux résultats.
 interface ICalculExemple : ::calcul::ICalcul
 {
 };
L'interface qui permet de lancer le calcul. Les méthodes définies par l'interface mère sont les suivantes:
  IParametres parametres(in ::objet::IConnexion c);
  IResultats  resultats(in ::objet::IConnexion c);
  rien        calcul(in ::objet::IConnexion c);
  tempsInt     dureeEstimee(in ::objet::IConnexion c);

Les deux premières méthodes ( qui sont déjà implantées dans DCalcul.java) permettent de récupérer les interfaces de paramètres et de résultats du calcul à partir d'une IConnexion. Une IConnexion est un objet permettant d'identifier de manière unique les accès au serveur de calcul.
Les méthodes calcul et dureeEstimee devront être implantées dans votre fichier java.
};
#endif
Fin du module

La génération des fichiers java

Le fichier IDL définit les objets qui seront accessibles par l'intérmédiaire de l'architecture CORBA. Pour utiliser ces objets distribués, il faut créer les "classes" qui vont effectuer les tâches définies. Dans le cas de Fudaa, le code IDL est projeté dans le langage Java, le bus utilisé est celui du JDK 1.3 (Corba 2.0) et l'héritage des classes d'implantation est assurée par la technique de délégation ("tie"). Il est conseillé de lire le document de SUN sur le langage IDL (cf la page des liens) et plus particulièrement la partie "Implementing Inheritance" du chapitre "Extending Hello World".

Il s'agit maintenant de générer le source java correspondant au fichier exemple.idl. La manière la plus simple pour générer le code est d'utiliser l'outil ant et la cible IDLJ ( équivalent du compilateur IDL-to-Java ). Sous unix/linux, il est possible d'utiliser le script jaidl1.3 et la commande jaidl1.3 code/exemple

Dans notre exemple, les fichiers seront générés dans le dossier dodico_java_genere/org/fudaa/dodico/corba/exemple. Ces classes doivent être compilées dans le dossier classes de dodico: la cible IDLJ de ant (de dodico !) ou le script jacgen:

ant IDLJ

Il est maintenant possible d'écrire les classes d'implantation des 3 interfaces.

L'équivalence IDL-JAVA

Les structures IDL deviennent des classes contenant des champs publiques. Voici un exemple d'utilisation de SParametres:

SParametres param=newSParametres();
param.nom="essai1";
param.t=5;

une interface IDL représente un objet distant et plusieurs fichiers importants sont générés pour une interface. Pour l'interface ICalculExemple:

  • -_ICalculExempleStub.java:
    • une classe du côté client (le "stub") qui transmet au serveur les commandes de l'application cliente
  •  
  • -ICalculExemple_Tie.java:
    • une classe du côté serveur (le "skeleton") qui reçoit les invocations distantes et les transmet aux classes exécutantes ( "servant" )
  •  
  • -ICalculExempleHelper.java, ICalculExempleHolder.java,...:
    • des classes utilitaires
  •  
  • -ICalculExempleOperations.java :
    • une interface qui sera implantée par votre classe d'implantation DCalculExemple.java (la classe "servant").

Etape 3 : Les classes d'implantation java

Exemple de structure

Il s'agit maintenant de créer et de compléter les 3 classes (DParametresExemple, DCalculExemple et DResultatsExemple) qui se trouveront dans le dossier dodico_java_ecrit/org/fudaa/dodico/exemple/. Nous prendrons le cas de DCalculExemple:

package org.fudaa.dodico.exemple;

import org.fudaa.dodico.corba.objet.*;
import org.fudaa.dodico.objet.*;
import org.fudaa.dodico.corba.calcul.*;
import org.fudaa.dodico.calcul.*;
import org.fudaa.dodico.corba.exemple.*;
import org.fudaa.dodico.fortran.*;

Ce sont les importations généralement utilisées.
publicclass DCalculExemple
  extends DCalcul
  implements ICalculExempleOperations,ICalculExemple
{
Cette classe sera la classe déléguée à ICalculExemple_Tie ( cf le constructeur de DObjet et le document de SUN). Elle doit ainsi implanter l'interface ICalculExempleOperations. Grâce au support de l'héritage, il est possible d'hériter de la classe DCalcul.
  publicDCalculExemple()
  {
    super();
  }
Ce constructeur par défaut permettra au script de prendre en compte cette classe et de l'ajouter à l'usine.
  public String description()
  {
    return"Exemple, "
      +super.description();
  }
Cette méthode est issue de l'interface ITache.
  publicvoidcalcul(IConnexion c)
  {
  }
Cette méthode est issue de l'interface ICalcul.
}
 

A ce stade du développement, vous pouvez écrire la structure des 2 autres classes d'implantation DParametresExemple.java et DResultatsExemple.java. Pour compiler vos classes, la cible compileJavaEcrit de ant ou la ligne de commande jac exemple pourront être utilisées.

L'usine

Pour créer les objets à distance, une usine est utilisée. Celle-ci est générée automatiquement à partir des sources idl et java ( voir les spécifications de nommage pour connaître les quelques règles d'écriture).

le fichier idl general/usine.idl et java usine/DUsine.java seront crées par la cible usine. Ces fichiers devront être également compilés. La cible build permet de chaîner automatiquement toutes les tâches nécessaires (il est fortement conseillé de l'utiliser au début).

!!! Si le fichier idl est modifié vous devez reprendre les étapes précédentes : generation du code java (la tâche IDLJ), compilation du code généré (compileJavaGenere) et compilation de votre code (compile).

!!! Si des interfaces ont été ajoutées ou supprimées, il faut régénérer l'usine.

-La cible IDLJ permet de chaîner automatiquement toutes les tâches nécessaires. Pour recompiler le java, utiliser la tâche build.

Les méthodes de lecture et d'écriture des fichiers d'entrée-sortie

Ces méthodes sont des méthodes statiques qui se trouvent dans les classes DParametresExemple et DResultatsExemple. En général, elles utilisent les classes FortranReader ou FortranWriter qui offrent des méthodes très pratiques pour gérer les fichiers de données. Ces méthodes permettent de faire le lien entre les fichiers du code et les structures IDL.

Pour notre cas, deux méthodes pourront être créées dans le fichier DParametresExemple:

publicstaticvoidecritParametres(File _fic , SParametres _p)
  throws IOException
ecriture dans le fichier _fic des paramètres correspondant à la structure _p
publicstaticvoidecritParametres02(File _fic , SParametres02 _p)
  throws IOException
idem

et une dans DResultatsExemple:

publicstaticSResultatslitResultats(File _fic )
  throws IOException
Creation d'une structure à partir des données du fichier _fic .

La méthode calcul de la classe DCalculExemple

Cette méthode doit permettre de :

  • -écrire les fichiers de paramètres du code,
  • -trouver et lancer le code de calcul,
  • -lire le(s) fichier(s) de résultats,
  • -informer de l'état d'avancement des opérations.

La fichier calcul/DCalcul.java fournit des méthodes intéressantes pour gérer les fichiers, le chemin du serveur, ... Pour écrire cette méthode, vous pouvez également vous aider des projets curvi ou vag.

La classe serveur par défaut

Pour chaque code, une classe serveur simple est proposée : il s'agit de connecter un objet calcul à l'ORB. Dans notre cas, ce sera la classe ServeurExemple (cf vag).

Etape 4 : tests

Vous trouverez ci-dessous une classe qui permet de tester l'interface de communication de votre code. Ce test doit connaître le chemin du serveur (le code exécutable) et un fichier de parametres de ce code. Une méthode permettant la lecture du fichier de paramètres doit être créée pour utiliser cet exemple (il est également possible d'instancier la structure de paramètres dans la classe test).


package org.fudaa.dodico.exemple;


import java.io.File;

import org.fudaa.dodico.objet.CDodico;
Cette classe utilitaire est très importante. Elle gère l'ORB et les connexions des objets à ce bus. Elle permet également de créer ou trouver une instance de classe usine.


import org.fudaa.dodico.corba.objet.IConnexion;
import org.fudaa.dodico.corba.objet.IPersonne;
import org.fudaa.dodico.corba.objet.IOrganisme;
Ces trois objets permettent de définir la personne qui utilise un code de calcul. Une IPersonne doit demander une connexion (IConnexion) à un code de calcul avant de pouvoir l'utiliser.


import org.fudaa.dodico.corba.usine.IUsine;
L'usine qui permet de construire les objets à distance.


import org.fudaa.dodico.corba.exemple.ICalculExemple;
import org.fudaa.dodico.corba.exemple.IParametresExemple;
import org.fudaa.dodico.corba.exemple.IParametresExempleHelper;
import org.fudaa.dodico.corba.exemple.IResultatsExemple;
Les interfaces CORBA du code de calcul. IParametresExempleHelper est utilisée pour "caster" les IParametresExemple.


import org.fudaa.dodico.corba.exemple.SParametresExemple;
import org.fudaa.dodico.corba.exemple.SResultatsExemple;
Les structures qui seront échangées entre le serveur de calcul et l'application cliente.


publicclass ClientExemple
{

  publicstaticvoidmain( String[] args)
  {
   if(args.length!=2)
   {
    System.out.println("ClientExemple <serveur> <fichier_entree>");
    System.exit(1);
   }
   System.out.println("serveur "+args[0]);
   System.setProperty("FUDAA_SERVEUR",args[0]);
   File entree=newFile(args[1]+".extension");
   if( !entree.exists() )
   {
    System.out.println(entree.getAbsolutePath()+" non trouvé");
    System.exit(1);
   }
Dans cette partie, les paramètres passés à la méthode main sont testés: le premier doit être le chemin du serveur et le deuxième le chemin du fichier de paramètres. Le chemin du serveur est spécifié grâce à la propriété FUDAA_SERVEUR.

   System.out.println("création du serveur");
   //Creation de l'usine de base
   UsineLib.setAllLocal(false);
   IUsine usine=UsineLib.creeUsine();
   //Creation d'une personne (et son organisme)
   IPersonne p=usine.creeObjetPersonne();
   IOrganisme o=usine.creeObjetOrganisme();
Grâce à la classe CDodico, une usine locale est créée. A l'aide de cette dernière, une IPersonne et une IConnexion sont créées à leur tour.

   o.intitule("sans");
   p.organisme(o);
   p.nom("test");
L'organisme et la personne sont renseignés.

   //Creation du serveur de calcul et connexion de la personne
   ICalculExemple calcul=usine.creeExempleCalculExemple();
Création de l'interface de calcul.

   IConnexion connexion=calcul.connexion(p);
Demande de connexion au serveur.

  IParametresExemple params=
    
IParametresExempleHelper.narrow(calcul.parametres(connexion));
A partir de la connexion, nous obtenons une instance de IParametres. Pour la caster en IParametresExemple, la classe utilitaire IParametresExempleHelper doit être utilisée.
!!!Toujours utiliser cette méthode pour "caster" des interfaces CORBA

   System.out.println("lecture des parametres");
   try
   {
    params.parametresExemple(DParametresExemple.litParametresExemple(args[1]));
Lecture du fichier de paramètres et affectation des structures obtenues.

    System.out.println("lancement calcul");
    calcul.calcul(connexion);
Lancement du calcul.

    System.out.println("calcul termine");
   }
   catch(Exception e)
   {
    System.out.println(e);
   }
  
  }
}
 

-La partie dodico est terminée. La prochaine étape: construction de l'interface graphique