Salome HOME
46e6b92571d8a9cdd7f37ddbbed3f0e92ca17110
[modules/yacs.git] / doc / salome.rst
1
2 Composant Salomé
3 ================
4
5
6 Principe
7 --------
8
9 Un composant Salomé est un composant CORBA tel que décrit au chapitre
10 précédent, utilisant des services du noyau Salomé. Il faut également  "déclarer"
11 ce composant auprès de Salomé (i.e. fournir ou compléter  des fichiers de
12 ressources Salomé avec des informations relatives à ce  composant).    Les
13 différentes opérations à effectuer sont :
14
15 1. adapter le fichier IDL,
16
17 2. déclarer le composant auprès du catalogue de modules de Salomé,
18
19 3. modifier la classe d'implémentation (C++ ou python) pour
20
21    - suivre l'adaptation du fichier IDL (point 1),
22    - permettre la supervision du composant par Salomé, dans les différents services du composant.
23    - préparer l'utilisation du service de notification (envoi de messages pour suivre 
24      le déroulement des calculs dans le composant) - optionel (mais utile),
25
26 4. déclarer les éventuelles ressources graphiques.
27
28
29 Fichier IDL
30 -----------
31
32
33 Principe
34 ^^^^^^^^
35
36 La description IDL est semblable à celle d'un composant CORBA standard avec  les
37 particularités :
38
39 * le composant doit faire partie du module (CORBA) de base ``Engines``,
40
41 * le composant doit hériter du composant de base de Salomé :
42   ``Engines::Component``  (défini dans le fichier IDL ``"SALOME_Component.idl"``),
43
44 * les services du composant peuvent avoir des paramètres ``in``,    ``out``
45   et/ou une valeur de retour, mais pas de paramètres ``inout``.
46
47
48 **Remarques**
49
50   #. Le module ``Engines`` regroupe tous les composants de Salomé, autres  que les
51      composants centraux de Salomé.
52
53   #. Le composant de base ``Engines::Component`` permet de ne pas devoir
54      redéfinir pour chaque composant ajouté au système, les services communs  (arrêt,
55      reprise, etc.).
56
57   #. Ceci n'est pas une limitation, un paramètre ``inout`` peut se  découpler en
58      un paramètre ``in`` et un paramètre ``out`` (de toute  façon, c'est sous cette
59      forme que le verront les clients python).
60
61
62 Exemple 9 (début)
63 ^^^^^^^^^^^^^^^^^
64
65 Reprenons le fichier IDL ``alglin.idl`` et adaptons-le :
66
67
68 ``alglin.idl``
69
70 .. include:: ./exemples/exemple9/alglin.idl
71    :literal:
72
73 **Remarque**
74   Il faut faire attention quand on définit des structures dans l'IDL (comme la
75   structure ``vecteur`` dans ``alglin.idl``). Le nom choisi ``vecteur`` risque
76   d'être  déjà "réservé" par un autre composant Salomé.
77
78
79 Exemple 10 (début)
80 ^^^^^^^^^^^^^^^^^^
81
82 Des modifications analogues sont effectuées sur le fichier IDL   ``FreeFem.idl`` :
83
84
85 ``FreeFem.idl``
86
87 .. include:: ./exemples/exemple10/FreeFemComponent.idl
88    :literal:
89
90
91 Inscription au catalogue de modules
92 -----------------------------------
93
94 Pour être utilisables dans Salomé, les composants doivent s'inscrire auprès  de
95 l'un des catalogues de modules de Salomé.    Ce catalogue est réparti entre
96 plusieurs fichiers (catalogue général,   catalogue utilisateur). On supposera
97 que le composant sera déclaré dans  le catalogue personnel d'un utilisateur.
98 Le fichier de catalogue de composants est un fichier XML qui contient
99
100 #. la liste des services du composant et leurs paramètres,
101
102 #. la (les) machine(s) où le composant peut être chargé en mémoire,  le nom du
103    fichier contenant l'icone du composant, des informations de version,
104    commentaires, service par défaut, etc (ces informations sont optionelles).
105
106 On peut compléter à la main ce catalogue ou utiliser un utilitaire  fourni par
107 Salomé qui génère les informations du point 1 ci-dessus  (il faudra malgré tout
108 éditer le fichier pour entrer les informations  du point 2).    Cet outil est
109 disponible dans l'interface graphique Salomé (menu ``Tools->Catalog Generator``)
110 en indiquant le nom du catalogue (fichier XML) et le nom  du fichier IDL du
111 composant.
112
113
114 Classe d'implémentation C++
115 ---------------------------
116
117 **On supposera dans ce paragraphe, que le fichier IDL définit une classe CORBA :
118 A  et qu'on utilisera la classe d'implémentation C++ : A_impl.**
119
120
121 Mise en conformité avec l'IDL du composant
122 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
123
124 Pour adapter les classes d'implémentation CORBA/C++ standards (telles  que vues
125 au chapitre précédent), il faut :
126
127 #. insérer le fichier ``SALOMEconfig.h`` :   ::
128
129              #include <SALOMEconfig.h>
130
131    Le fichier ``SALOMEconfig.h`` contient un certain nombre de définitions  utiles
132    pour assurer l'indépendance du code de la classe d'implémentation  par rapport à
133    la version de CORBA utilisée.
134
135 #. insérer ensuite le fichier ``SALOME_Component_i.hxx``     ::
136
137              #include "SALOME_Component_i.hxx"
138
139    qui contient l'interface de la classe d'implémentation C++ du composant  de base
140    de Salomé
141
142 #. pour la classe CORBA qui est implémentée, ajouter la ligne :     ::
143
144              #include CORBA_SERVER_HEADER(A)
145
146    ``CORBA_SERVER_HEADER`` est une macro définie dans ``SALOMEconfig.h``  et qui
147    assure l'indépendance des noms de fichiers d'inclusion CORBA par  rapport à
148    l'implémentation de CORBA utilisée.
149
150 #. pour chaque classe CORBA qui est utilisée dans la classe  d'implémentation,
151    ajouter la ligne :     ::
152
153             #include CORBA_CLIENT_HEADER(<nom de la classe CORBA>)
154
155    ``CORBA_CLIENT_HEADER`` est une macro définie dans ``SALOMEconfig.h``  et qui
156    assure l'indépendance des noms de fichiers d'inclusion CORBA par  rapport à
157    l'implémentation de CORBA utilisée.
158
159 #. faire dériver la classe d'implémentation de celle du composant  Salome de
160    base :     ::
161
162       class A_impl :
163            public POA_Engines::A,
164            public Engines_Component_i {
165
166 #. définir le (seul) constructeur de la façon suivante dans le fichier  d'entête
167    C++ (.hxx) :     ::
168
169            A_impl(CORBA::ORB_ptr orb,
170                   PortableServer::POA_ptr poa,
171                   PortableServer::ObjectId * contId, 
172                   const char *instanceName,
173                   const char *interfaceName);
174
175    et dans le fichier d'implémentation C++ (.cxx) :     ::
176
177            A_impl:: A_impl
178                      (CORBA::ORB_ptr orb,
179                       PortableServer::POA_ptr poa,
180                       PortableServer::ObjectId * contId, 
181                       const char *instanceName, 
182                       const char *interfaceName) :
183                 Engines_Component_i(orb, poa, contId, 
184                                     instanceName, interfaceName)
185            {
186              _thisObj = this ;
187              _id = _poa->activate_object(_thisObj);
188            }
189
190    Ce constructeur sera éventuellement responsable de la création et  de
191    l'initialisation de l'objet interne associé au composant CORBA.
192
193 #. si des structures sont définies par le fichier IDL dans le module  Engines,
194    adapter les déclarations des méthodes de la classe d'implémentation.
195
196 L'exemple ci-dessus illustre les modifications effectuées sur l'exemple 6.
197
198 .. _remsuper:
199
200
201 Permettre la supervision du composant
202 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
203
204 Pour pouvoir piloter le composant depuis la supervision, il faut  insérer dans
205 chaque service du composant (i.e. dans chaque méthode  de la classe
206 d'implémentation qui est appelée lors d'une requète  CORBA),
207
208 * au début, l'instruction :   ::
209
210      beginService(<nom du service>);
211
212 * à la fin, l'instruction :   ::
213
214      endService(<nom du service>);
215
216 Ces deux instructions signalent à la supervision de Salomé  que le service du
217 composant a bien reçu la requète CORBA (beginService)  et que l'exécution du
218 service s'est bien terminée (endService).    
219
220 **Remarque**
221   Mettre beginService et endService
222   dans les méthodes de la classe d'implémentation d'un composant  déclare à Salomé
223   que le composant est "supervisable". Ce n'est pas  une assurance que l'on pourra
224   utiliser ce composant sans précautions  dans le cas où le composant possède un
225   état interne modifié par  un ou plusieurs services.    
226   
227   **Exemple**
228     On considère un composant ayant une variable interne ``Quantite``  et deux services :
229
230     * ``S1(x) : Quantite = Quantite + x;`` retourne ``Quantite`` et
231
232     * ``S2(x) : Quantite = Quantite * x;`` retourne ``Quantite``.
233
234     Il n'est pas possible *a priori* de connaître la valeur de  ``Quantite`` après
235     exécution du graphe de calcul sur la figure suivante.
236
237 .. _figpara:
238
239
240 .. image:: images/parallele.png
241      :width: 26ex
242      :align: center
243
244 .. centered::
245      Graphe de calcul contenant des branches parallèles
246
247 Utilisation de la notification
248 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
249
250 Pour signaler l'utilisation de la notification (qui provoquera l'ouverture
251 d'une connexion à un canal d'événements), il faut modifier  le constructeur de
252 la classe d'implémentation comme suit :     ::
253
254         A_impl:: A_impl
255                   (CORBA::ORB_ptr orb,
256                    PortableServer::POA_ptr poa,
257                    PortableServer::ObjectId * contId, 
258                    const char *instanceName, 
259                    const char *interfaceName) :
260              Engines_Component_i(orb, poa, contId, 
261                                  instanceName, interfaceName, 1)
262         {
263           _thisObj = this ;
264           _id = _poa->activate_object(_thisObj);
265         }
266
267 où on a ajouté le paramètre "1" à la fin de l'appel du constructeur  de
268 ``Engines_Component_i``.    Le composant pourra ensuite utiliser l'instruction
269 ::
270
271    void sendMessage(const char *event_type, const char *message);
272
273 pour envoyer des messages indiquant le déroulement du calcul  ou une situation
274 anormale, etc. Ces messages seront visibles de  l'utilisateur de Salomé.    Le
275 premier paramètre indique le type de message ("warning", "step",  "trace",
276 "verbose"), le second paramètre, le contenu (chaîne de   caractères) du message.
277
278
279 Connexion à l'objet "fabrique" d'un conteneur
280 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
281
282 Afin de permettre le chargement et l'initialisation d'un composant  par un
283 conteneur, il faut fournir une fonction C dont le nom  et le code sont imposés :
284 ::
285
286    extern "C"
287    {
288      PortableServer::ObjectId * <nom du composant>Engine_factory(
289                                   CORBA::ORB_ptr orb,
290                                   PortableServer::POA_ptr poa,
291                                   PortableServer::ObjectId * contId,
292                                   const char *instanceName,
293                                   const char *interfaceName)
294      {
295        <classe d'implementation> * O
296          = new <classe d'implementation>(orb, poa, contId, 
297                                          instanceName, interfaceName);
298        return O->getId() ;
299      }
300    }
301
302 ``<nom du composant>`` (ou nom de la classe CORBA, ``A`` ici)  et ``<classe
303 d'implementation>`` (``A_impl`` ici) sont  spécifiques à chaque composant.
304 Cette fonction est appelée par le conteneur lors du chargement  d'un composant.
305 Elle crée un objet CORBA qui réceptionnera les requètes  au composant et les
306 transmettra au différents services du composant.
307
308
309 Exemple 9 (suite)
310 ^^^^^^^^^^^^^^^^^
311
312 Reprenons les fichiers d'implémentation ``alglin_i.hxx`` et   ``alglin_i.cxx``
313 et adaptons-les :
314
315
316 ``alglin_i.hxx``
317
318 .. include:: ./exemples/exemple9/alglin_i.hxx
319    :literal:
320
321
322 ``alglin_i.cxx``
323
324 .. include:: ./exemples/exemple9/alglin_i.cxx
325    :literal:
326
327
328 Classe d'implémentation python
329 ------------------------------
330
331 **On supposera dans ce paragraphe, que le fichier IDL définit une classe CORBA :
332 B  et qu'on utilisera la classe d'implémentation python : B.**    La démarche
333 est analogue au cas de l'interface serveur C++ :
334
335
336 Mise en conformité avec l'IDL du composant
337 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
338
339 #. importer la classe du composant de base :     ::
340
341       from SALOME_ComponentPy import *
342
343 #. faire dériver la classe d'implémentation de celle du composant  Salome de
344    base :     ::
345
346       class B(Engines__POA.B,
347               SALOME_ComponentPy_i):
348
349 #. le constructeur de la classe d'implémentation doit débuter par :     ::
350
351           def __init__(self, orb, poa, this, containerName,
352                        instanceName, interfaceName):
353               SALOME_ComponentPy_i.__init__(self, orb, poa, this, 
354                                             containerName, instanceName, 
355                                             interfaceName, 0)
356
357
358 Permettre la supervision du composant
359 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
360
361 Pour pouvoir piloter le composant depuis la supervision, il faut  insérer dans
362 chaque service du composant (i.e. dans chaque méthode  de la classe
363 d'implémentation qui est appelée lors d'une requète  CORBA),
364
365 * au début, l'instruction :   ::
366
367      beginService(<nom du service>);
368
369 * à la fin, l'instruction :   ::
370
371      endService(<nom du service>);
372
373 Ces deux instructions signalent à la supervision de Salomé  que le service du
374 composant a bien reçu la requète CORBA (beginService)  et que l'exécution du
375 service s'est bien terminée (endService).    Même remarque que dans le cas C++
376 (:ref:`remsuper`)
377
378
379 Utilisation de la notification
380 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
381
382 Pour signaler l'utilisation de la notification, il faut modifier  le
383 constructeur de la classe d'implémentation comme suit :     ::
384
385        def __init__(self, orb, poa, this, containerName,
386                     instanceName, interfaceName):
387            SALOME_ComponentPy_i.__init__(self, orb, poa, this, 
388                                          containerName, instanceName, 
389                                          interfaceName, 1)
390
391 où on a ajouté le paramètre "1" à la fin de l'appel du constructeur  de
392 ``SALOME_ComponentPy_i``.    Le composant pourra ensuite utiliser l'instruction
393 ::
394
395    sendMessage(event_type, message);
396
397 pour envoyer des messages indiquant le déroulement du calcul  ou une situation
398 anormale, etc. Ces messages seront visibles de  l'utilisateur de Salomé.    Le
399 premier paramètre indique le type de message ("warning", "step",  "trace",
400 "verbose"), le second paramètre, le contenu (chaîne de   caractères) du message.
401
402
403 Exemple 10 (suite)
404 ^^^^^^^^^^^^^^^^^^
405
406 Reprenons le fichier d'implémentation ``FreeFem.py`` et adaptons le :
407
408
409 ``FreeFemComponent.py``
410
411 .. include:: ./exemples/exemple10/FreeFemComponent.py
412    :literal:
413
414
415 Utilisation de l'environnement de compilation et d'exécution de  Salomé
416 -----------------------------------------------------------------------
417
418 On utilisera les autotools comme Salomé.
419
420 Utilisation des structures de données fournies par Salomé ou renvoyées par le composant
421 ---------------------------------------------------------------------------------------
422
423 Pour cette partie, on se référera aux spécifications CORBA [CORBA]_,  et en
424 particulier les spécifications IDL - langages [LANG]_ ou aux   différents
425 manuels CORBA, par exemple [HENVIN]_ (C++) et   [PyCorba]_ (python).
426
427
428 Maillages et champs MED
429 ^^^^^^^^^^^^^^^^^^^^^^^
430
431 Pour cette partie, on se réfèrera à la documentation de MED et MEDMemory
432 [MEDDoc]_ et [MEDMemory]_.
433