]> SALOME platform Git repositories - modules/yacs.git/blob - doc/progdsc.rst
Salome HOME
f79c09a92431eb5d5140091f759ade4c049230b1
[modules/yacs.git] / doc / progdsc.rst
1 .. _progdsc:
2
3 Introduction au modèle de programmation DSC pour les composants Salomé
4 ======================================================================
5
6 Cette introduction a pour objectif de fournir les notions essentielles pour utiliser 
7 l'extension DSC (Dynamic Software Component) dans des composants Salomé. Il est 
8 destiné aux développeurs d'applications Salomé qui doivent intégrer des codes de 
9 calculs sous la forme de composants Salomé ou de services du superviseur.
10
11 Le principe du modèle de programmation
12 ----------------------------------------
13
14 Le modèle de programmation DSC est fourni par le noyau Salomé et est disponible 
15 non seulement pour les services mais aussi pour des composants Salomé sans supervision.
16 Une application Salomé qui souhaite utiliser l'extension DSC suit toujours ce principe :
17
18 1. Les différents programmes, codes, services qui composent l'application déclare 
19    dans la phase d'initialisation les différents ports disponibles.
20 2. Ensuite le système (par exemple YACS ou un script utilisateur) connecte les 
21    différents ports pour mettre en place les différentes communications entre les codes.
22 3. Les codes sont lancés. Lorsqu'ils souhaitent utiliser un de leur port DSC, le code 
23    demande au système un pointeur vers son port. Le système vérifie alors que le port 
24    a été bien connecté et/ou bien déclaré.
25 4. Les codes utilisent les ports DSC.
26
27 Apports de l'extension DSC
28 ---------------------------------
29
30 Les apports principaux de l'extension DSC au modèle de programmation de Salomé sont les 
31 suivants:
32
33 1. Il permet de mettre en oeuvre les ports datastream dans Salomé.
34 2. Il permet d'utiliser l'outil de couplage Calcium au sein d'un schéma de calcul sans 
35    dépendre de l'implémentation de Calcium hors Salomé. Une meilleure intégration de ce 
36    type de ports est ainsi obtenue ainsi qu'une plus grande flexibilité dans les types de 
37    données possibles.
38 3. Il offre la possibilité d'ajouter des ports de type interface dans des services.
39
40 Les ports de type interface
41 +++++++++++++++++++++++++++++
42
43 DSC permet d'ajouter des ports de type interface à des composants et donc à des 
44 services. Les ports datastream ne sont qu'une spécialisation de ces ports d'interfaces. 
45 Cette interface est décrite par le biais d'une interface CORBA. Elle doit donc être 
46 implémentée par un objet CORBA qui peut soit être le composant lui même ou un objet que 
47 le composant utilise.  A chaque port d'interface, des propriétés peuvent lui être 
48 attachées grace à un objet spécifique de configuration.
49
50 Les ports datastream Calcium
51 +++++++++++++++++++++++++++++
52
53 Le noyau Salomé propose une nouvelle implémentation des ports Calcium. Ces ports 
54 sont des ports d'interfaces, ils peuvent donc être utilisés comme les autres ports 
55 d'interfaces par le biais de l'API C++ ou ils peuvent être utilisés comme avec Calcium 
56 par le biais d'une interface C ou FORTRAN. Enfin, cette nouvelle implémentation a été 
57 réalisé avec le soucis de pouvoir porter une application Calcium très rapidement dans 
58 Salomé.
59
60 Les connexions entre les ports DSC
61 ------------------------------------
62
63 Les ports DSC peuvent être entrant ou sortant. Les ports sortant sont appelés 
64 << uses >> car ils permettent l'utilisation d'une interface externe au composant ou au 
65 service. Les ports entrant sont appelés << provides >> car ils fournissent l'implémentation 
66 de l'interface du port. 
67
68 Les ports des services sont décrits dans un fichier XML que le gestionnaire de 
69 catalogues lit lors de la création d'un schéma de calcul. En revanche les ports ne 
70 sont pas décrits dans la déclaration CORBA du service. C'est pourquoi ils sont créés 
71 et ajoutés dynamiquement lors de la création et de l'exécution du service (en comparaison
72 avec des modèles plus statiques tel que le CORBA Component Model). DSC ajoute des méthodes 
73 aux composants pour déclarer des ports d'interfaces.
74
75 ::
76
77   void add_provides_port(...);
78   void add_uses_port(...);
79   Ports::Port get_provides_port(...);
80   uses_port get_uses_port(...);
81
82 Des méthodes sont fournies pour permettre la connexion de ports uses avec des ports 
83 provides du même type (c'est à dire de la même interface CORBA). De plus, DSC averti 
84 le code utilisateur des modifications des connexions des ses ports par le biais de méthodes 
85 de callback.
86
87 ::
88
89   void connect_provides_port(...);
90   void connect_uses_port(...);
91   boolean is_connected(...);
92   void disconnect_provides_port(...);
93   void disconnect_uses_port(...);
94   void provides_port_changed(...);
95   void uses_port_changed(...);
96
97 Les connexions entre les ports uses et provides permettent différentes combinaisons. Un port 
98 uses peut être connecté à plusieurs ports provides. De même un port provides peut être connecté 
99 à plusieurs ports uses. Enfin, les ports uses connaissent les ports provides auxquels ils 
100 s'adressent tandis que les ports provides ne connaissent pas à priori les ports uses qui les 
101 ont appelés (Il est évidemment possible de rajouter des informations applicatives).
102
103 Les deux couches de programmation
104 ------------------------------------------------
105
106 Le modèle de composant DSC est divisé en deux parties : DSC_Basic et DSC_User. 
107
108 DSC_Basic est la couche basse de DSC. Elle fournit les fonctions de bases pour ajouter 
109 la notion de ports à un objet CORBA. Elle permet d'enregistrer les servants des ports provides,
110 déclarer des ports uses et les connecter. Il s'agit d'une couche dite basique car elle n'offre 
111 que peu de confort d'utilisation. Notamment, un port uses se présente sous la forme d'une 
112 séquence de références vers les ports provides auquel le port a été connecté. A charge à
113 l'utilisateur de gérer cette séquence et d'appeler manuellement les différentes ports provides 
114 lors de l'utilisation du port uses.
115
116 La couche DSC_User permet d'obtenir un plus haut niveau de programmation et d'encapsulation 
117 des ports. Tout d'abord, elle permet la création de services Salomé avec des ports datastream 
118 (ou d'interface) fournis par la plate-forme Salomé. Elle fournit une méthode d'initialisation 
119 que le superviseur va appeler avant l'exécution du service, méthode qui permet de déclarer 
120 correctement les ports des services. Enfin, elle offre une abstraction pour les ports uses et
121 provides. Les deux types de ports sont implémentés par des classes et l'utilisateur a ainsi
122 une vue uniforme des deux types ports : 2 classes (et non une séquence et une référence CORBA
123 comme dans la couche DSC_Basic). Un autre apport est la gestion automatique de la liste des 
124 ports provides connecté à un port uses. Le code utilisateur a une unique référence sur son 
125 port uses; à charge à l'implémentation du port uses de transmettre un appel vers les 
126 différentes connexions du port.
127
128 DSC par l'exemple
129 ------------------------------------------------
130
131 Nous allons maintenant découvrir les principes de la programmation DSC par le biais de 
132 différents exemples.
133
134 Le premier exemple met en place un composant avec un port provides. 
135 Le deuxième exemple met en place un deuxième composant avec un port uses qui va être 
136 connecté au port provides de l'exemple Hello World.
137 Le troisième exemple montre comment utiliser les ports datastream dans des services.
138 Le quatrième exemple montre comment utiliser le système de fabrique des ports datastream 
139 pour ajouter sa propre famille dans le modèle de programmation.
140 Enfin le cinquième exemple montre comment utiliser la nouvelle implémentation Calcium dans le 
141 cadre de Salomé.
142
143 Les exemples ci-dessous montre des exemples de programmation des composants. En revanche,
144 ils ne contiennent pas tout le code, seule les nouvelles parties seront décrites dans ce 
145 document. Vous pourrez trouver tout le code des exemples dans le module Salomé DSC_EXEMPLE_SRC.
146
147 Les deux premiers exemples ont pour objectif de faire comprendre comment manipuler des ports 
148 DSC par le biais de la couche DSC_Basic.  En revanche, il faut étudier le troisième exemple 
149 pour pouvoir créer des services avec des ports DSC par le biais de la couche DSC_User.
150
151 Pour récupérer les exemples, il faut être autoriser à accéder à la base subversion du projet pal.
152 Il suffit ensuite dans un shell unix de taper la ligne suivante :
153
154 svn co svn://<nom>@nepal/PAL/DSC_EXEMPLES_SRC/trunk  DSC_EXEMPLES_SRC
155
156 Hello World
157 +++++++++++++
158
159 Les sources de cet exemple se trouve dans le répertoire src/Ex_Serveur.
160
161 L'objectif de cet exemple est de créer un composant qui fournit un port provides. 
162 La figure ci-dessous illustre ce que nous allons faire. Le composant s'appelle Ex_Serveur 
163 et il fournit un port provides nommé Ex_Hello. Ce port provides fournit l'interface HelloWorld.
164
165 .. image:: images/progdsc_img1.png
166
167 La première étape est de définir les interfaces du composant et l'interface du port :
168
169 ::
170
171  Interface HelloWorld : Ports::Port {
172     void say_hello(in string name);
173  };
174
175  Interface Ex_Serveur : Engines::DSC {};
176
177 Le fichier IDL comprend tout d'abord la déclaration de l'interface du port provides que 
178 le composant va fournir. Il s'agit ici de l'interface HelloWorld. Cette interface est une
179 interface CORBA classique. En revanche, cette interface doit hériter de Ports ::Port pour
180 pouvoir être un port DSC. Le composant Ex_Serveur est aussi déclaré comme une interface CORBA 
181 qui hérite de l'interface Engines::DSC au lieu de Engines::Component. Il faut noter que le port
182 provides n'apparaît pas dans la définition IDL du composant. Le port est ajouté et déclaré 
183 dans les sources de l'implémentation du composant. Il est ajouté dynamiquement lors de 
184 l'exécution du composant.
185
186 Il s'agit maintenant d'implémenter le composant et le port provides. Le port provides est 
187 implémenté par le biais d'une classe C++ que nous appellerons HelloWorld_impl (voir dans 
188 les sources). Cette implémentation ne diffère en rien de celle d'un objet CORBA. Voici 
189 l'implémentation de la méthode say_hello :
190
191 ::
192
193  void 
194  HelloWorld_i::say_hello(const char * name) { 
195   std::cout << "Hello " << name << " ! " << std::endl;
196  }
197
198  
199 Il nous reste ensuite à implémenter le composant. Nous allons nous intéresser à la déclaration 
200 du port du composant et à la classe que le composant doit hériter. L'implémentation d'un 
201 composant (classe Ex_Serveur_i) qui veut utiliser des ports DSC doit hériter de la classe nommé 
202 Engines_DSC_i.. Bien entendu, elle doit aussi hériter de POA_Ex_Serveur.
203 Voici la déclaration de la classe Ex_Serveur_i :
204
205 ::
206
207  class Ex_Serveur_i :
208   public Engines_DSC_i,
209   public POA_Ex_Serveur
210  {
211
212   public:
213     Ex_Serveur_i(CORBA::ORB_ptr orb,
214                  PortableServer::POA_ptr poa,
215                  PortableServer::ObjectId * contId, 
216                  const char * instanceName, 
217                  const char * interfaceName);
218
219     virtual ~Ex_Serveur_i();
220  ...
221  };
222
223 Pour que le port provides soit utilisable, nous devons faire deux actions :
224 - Créer le port.
225 - Enregistrer le port dans le composant.
226
227 Pour réaliser ces deux étapes, nous ajoutons une méthode à la classe Ex_Serveur_i nommée 
228 register_ports() qui est appelé dans la fabrique du composant avant que celle-ci ne retourne 
229 la référence du composant au container. Cette méthode est implémentée de la façon suivante :
230
231 ::
232
233  void 
234  Ex_Serveur_i::register_ports() {
235
236  // Création du port provides
237  _Ex_Hello_port = new HelloWorld_i();
238  _Ex_Hello_port_properties = PortProperties_i();
239
240  // Enregistrement du port provides
241  add_provides_port(_Ex_Hello_port->_this(), 
242                    "Ex_Hello",
243                    _Ex_Hello_port_properties->_this());  
244  }
245
246 La méthode commence par la création du port provides. Il s'agit ici de créer le servant de 
247 l'interface CORBA du port. Il faut aussi créer un objet pour les propriétés du port. Dans
248 cet exemple, l'objet par défaut est utilisé (fourni par le noyau). Ensuite le port est 
249 enregistré dans le composant par le biais de la méthode add_provides_port fourni par DSC.
250
251 Le fait d'hériter de Engines_DSC_i oblige le composant à implémenter deux méthodes qui se 
252 nomment provides_port_changed() et uses_port_changed(). Ces deux méthodes sont des callbacks 
253 que le système utilise pour avertir le composant lorsque les connexions de ses ports ont 
254 évolués. La méthode provides_port_changed() permet d'être averti lorsque quelqu'un se connecte 
255 ou se déconnecte sur un de ses ports provides. Le callback indique notamment combien de 
256 client utilise le port provides (argument connection_nbr). Pour cet exemple, nous ne tenons 
257 pas compte de cette information. La méthode uses_port_changed() a quand à elle la même 
258 fonction que provides_port_changed(), mais pour les ports uses. Nous verrons dans le deuxième
259 exemple ses spécificités.
260
261 La documentation des différentes méthodes Engines_DSC_i sont fournis dans la documentation 
262 Doxygen du noyau de Salomé.
263
264 Cet exemple peut être exécuté par le biais du fichier de test src/tests/test_Ex_Serveur.py 
265 dans l'intrepréteur Salomé en mode terminal. Ce script illustre l'utilisation des ports DSC :
266  
267 ::
268
269  import LifeCycleCORBA
270  import Engines
271  import Ports
272  import HelloWorld_idl
273
274  lcc = LifeCycleCORBA.LifeCycleCORBA()
275  component = lcc.FindOrLoad_Component('FactoryServer', 'Ex_Serveur')
276  hello_port = component.get_provides_port("Ex_Hello", 0)
277  hello_port.say_hello("andre")
278
279 Après la création du composant par le biais du LifeCycleCORBA, le script utilise la 
280 méthode get_provides_port pour obtenir une référence sur le port provides du composant.
281 La référence obtenue est ensuite utilisée pour exécuter la méthode say_hello du port.
282
283 Hello World Client
284 +++++++++++++++++++++
285
286 Les sources de cet exemple se trouve dans le répertoire src/Ex_Client et dans src/Ex_Serveur.
287
288 L'objectif de cet exemple est de créer un nouveau composant qui va utiliser le port Ex_Hello 
289 du précédent exemple par le biais d'un port uses.
290
291 Voici une figure qui représente l'application:
292
293 .. image:: images/progdsc_img2.png
294
295 Le composant Ex_Client est décrit comme le composant Ex_Serveur dans le fichier IDL.
296 La seule différence est l'ajout dans son interface d'une méthode start(). Un composant 
297 ne contenant pas de fonction main lors de sa création, il nous faut une méthode pour lancer 
298 l'exécution du composant, d'où la définition de la méthode start. 
299
300 Voici la définition IDL du composant Ex_Client :
301
302 ::
303
304   Interface HelloWorld : Ports::Port {
305       void say_hello(in string name);
306   };
307
308   Interface Ex_Serveur : Engines::DSC {};
309
310   Interface Ex_Client : Engines::DSC {
311       void start() ;
312   } ;
313
314 Il faut maintenant implémenter le composant. Comme pour un port provides, un port uses 
315 doit être enregistré dans le composant avant qu'il ne soit utilisable par le composant. 
316 Un port uses correspond à une séquence de références vers les ports provides auxquels il 
317 a été connecté ; c'est pourquoi il n'est pas implémenté par une classe comme un port 
318 provides. En revanche, il est toujours possible d'ajouter des propriétés au port.
319 Voici le code de la méthode register_ports() pour le composant Ex_Client :
320
321 ::
322
323   void 
324   Ex_Client_i::register_ports() {
325
326     // Création de l'objet propriété pour le port uses.
327     _U_Ex_Hello_port_properties = new PortProperties_i();
328
329    // Ajout du port uses dans le composant
330     add_uses_port("IDL:HelloWorld:1.0", 
331      "U_Ex_Hello", 
332      _U_Ex_Hello_port_properties->_this());
333
334   }
335
336 Un port uses est associé à un type d'objet CORBA. La déclaration de ce type permet de 
337 vérifier si le port uses est connecté à un port provides compatible. Dans cet exemple, 
338 le type du port (déclaré dans l'IDL) est HelloWorld. CORBA propose pour chaque type IDL
339 une chaîne de caractère correspondant à ce type. Dans cet exemple il s'agit de :  
340 IDL:HelloWorld:1.0.
341
342 Il faut maintenant pouvoir utiliser le port uses. Pour cela, le composant demande au 
343 système de récupérer le port uses par le biais de la méthode get_uses_port(). Le port
344 prend la forme d'une séquence de référence sur les différents ports provides. Les références 
345 contenues dans cette séquence sont les ports provides auxquels le port uses a été connecté
346 à l'instant de l'appel de la méthode get_uses_port(). A chaque changement sur cette liste 
347 de référence, que ce soit un ajout ou un retrait, le système utilise la 
348 méthode use_port_changed() pour avertir le code utilisateur.
349
350 La méthode start() du composant Ex_Client va récupérer le port uses U_Ex_Hello et va 
351 appeler la méthode say_hello() sur la première référence. Voici le code de cette méthode :
352
353 ::
354
355   void 
356   Ex_Client_i::start() {
357
358    // Récupération du port ues U_Ex_Hello
359    Engines::DSC::uses_port * uport = get_uses_port("U_Ex_Hello"); 
360
361    // Récupération de la première référence de la séquence
362    _Ex_Hello_provides_port =  HelloWorld::_narrow((* uport)[0]);
363
364    // Appel de la méthode sur le port
365    _Ex_Hello_provides_port->say_hello(_instanceName.c_str());
366   }
367
368 Il faut noter qu'il faut transformer par le biais de la méthode _narrow les références 
369 contenues dans le port uses dans le type du port provides pour pouvoir utiliser le port provides.
370
371 Ports datastream et services
372 ++++++++++++++++++++++++++++++
373
374 Les sources de cet exemple se trouve dans le répertoire src/Ex_ProducteurConsommateur.
375
376 L'objectif de cet exemple est double. Tout d'abord, l'exemple montre comment mettre en 
377 oeuvre un service qui veut utiliser des ports DSC. Ensuite, il montre comment utiliser 
378 les ports datastream inclus dans le noyau de Salomé. 
379
380 Cet exemple met en place deux services qui vont être connectés par un port datastream. 
381 Le service produit du composant Producteur va produire un flux de donnée, et le composant 
382 consomme du composant Consommateur va afficher des données. 
383
384 Le service produit se termine lorsqu'il a envoyé toutes les données qu'il doit produire.
385 Le nombre de données à produire est déterminé par le port dataflow nombre. Le service 
386 consommateur a quand à lui besoin de connaître combien de données il doit récupérer avant
387 de se terminer. Ce nombre est, comme pour le service produit, déterminé par le port dataflow
388 nombre.
389
390 Voici la définition IDL des deux composants :
391
392 ::
393
394   interface Producteur : Engines::Superv_Component {
395     void produit(in long nombre);
396   };
397
398   interface Consommateur : Engines::Superv_Component {
399     void consomme(in long nombre);
400   };
401
402 Pour déclarer un composant qui va contenir des services utilisant des ports DSC, le composant 
403 doit hériter de l'interface Engines::Superv_Component et non plus de l'interface 
404 Engines::Component. En plus d'ajouter au composant l'interface de DSC,
405 Engines::Superv_Component ajoute la méthode init_service() qui est appelé par le
406 superviseur avant l'exécution du service. L'objectif de cette méthode est de permettre au 
407 concepteur du service d'initialiser les ports du service en vu de leur connexion avant le 
408 lancement effectif du service. Par rapport aux exemples précédents, init_service() a la même 
409 fonction que register_ports().
410
411 Il s'agit maintenant d'implémenter ces deux composants. La première différence avec un 
412 composant classique est qu'il faut hériter de la classe Superv_Component_i. De plus, il 
413 faut implémenter la méthode init_service().
414
415 Voici l'implémentation de la méthode init_service du composant Producteur : 
416
417 ::
418
419   CORBA::Boolean
420   Producteur_i::init_service(const char * service_name) {
421     CORBA::Boolean rtn = false;
422     string s_name(service_name);
423     if (s_name == "produit") {
424       add_port("BASIC_short", "uses", "produit_port");
425       rtn = true;
426     }  
427     return rtn;
428   }
429
430 La couche DSC_User qui implémente la classe Superv_Component_i fournit de nouvelles méthodes 
431 pour l'ajout des ports uses et provides. Il s'agit des méthodes de la famille add_port (Voir 
432 la documentation doxygen de Salomé). Ces méthodes ont pour objectif de permettre la création 
433 et l'enregistrement d'un port du service en une seule étape. De plus, elles permettent 
434 d'utiliser les ports datastream prédéfinis dans le noyau Salomé. 
435
436 Dans le cas du service produit, nous avons choisi d'utiliser le port datastream BASIC_short. 
437 Lorsque le noyau Salomé fournit un port datastream, il fournit toujours l'implémentation pour 
438 le port provides et pour le port uses. La première partie du nom (BASIC) identifie la famille 
439 de port datastream (comme CALCIUM ou PALM par exemple). La deuxième partie du nom contient le 
440 type de donnée transmis, dans cet exemple, un short. Ce type de port constitue le premier 
441 paramètre de la méthode add_port. Les deux autres arguments sont le type de port DSC (uses ou 
442 provides) et le nom du port dans le composant.
443
444 Lorsqu'il va s'agir d'utiliser ce port dans le service, il va falloir, comme dans les exemples 
445 précédent, récupérer une référence sur le port. Pour cela de nouvelles méthodes nommées 
446 get_port sont disponibles (à l'image des add_port). Voici un exemple de code pour utiliser 
447 la méthode get_port :
448
449 ::
450
451   uses_port * my_port = NULL;
452   get_port(my_port, "produit_port");
453   if (my_port != NULL) {
454    for (CORBA::Long i = 0; i < nombre; i++) {
455      data_short_port_uses * the_port = dynamic_cast<data_short_port_uses * >(my_port);
456         the_port->put(10);
457    }
458   }
459
460 La méthode get_port a deux arguments. Le premier va contenir un pointeur vers le port et le 
461 deuxième indique le nom du port demandé. Après l'appel de la méthode get_port, un pointeur 
462 générique est obtenu. On change ensuite son type avec le type de port attendu par le biais 
463 d'un dynamic_cast. Il est alors possible d'utiliser le port.
464
465 Pour permettre plus de commodité dans la programmation, la couche DSC_User propose plusieurs 
466 signatures pour les méthodes get_port et add_port. Par exemple, le composant Consommateur 
467 utilise les versions template de ces méthodes pour l'ajout et la récupération du code.
468
469 ::
470
471   data_short_port_provides * my_port = NULL;
472   my_port = get_port<data_short_port_provides>("consomme_port");
473   if (my_port != NULL)
474   {
475     for (CORBA::Long i = 0; i < nombre; i++) {
476        cout << "Hello, I receive : " << my_port->get() << endl;
477     }
478   }
479
480 La liste des différents types de ports fournis par le Noyau de Salomé est disponible dans 
481 la documentation Doxygen du noyau Salomé.
482
483 Ajouter des ports datastream et/ou d'interfaces
484 +++++++++++++++++++++++++++++++++++++++++++++++++
485
486 Les sources de cet exemple se trouve dans le répertoire src/Ex_ProducteurConsommateur_Adv.
487
488 L'objectif de cet exemple est de montrer les mécanismes pour ajouter ces propres types de 
489 ports dans la couche DSC_User. Pour cela, cet exemple explique comment remplacer le port 
490 BASIC_short de l'exemple précédent par son propre port. Etant donné que cet exemple est 
491 quasiment identique au niveau des composants, nous nous intéresserons uniquement dans ce 
492 document à la déclaration et l'implémentation du port.
493
494 Une famille de port Datastream (ou d'interface) contient deux types d'objets différents:
495
496 1. Une fabrique.
497 2. L'implémentation des ports.
498
499 La couche DSC_User connaît les types de port Datastream par le biais du design pattern 
500 fabrique. Pour chaque famille, une fabrique est enregistrée à la création du composant. 
501 Elle est ensuite utilisée par le composant dans les méthodes add_port(...) pour créer et 
502 enregistrer les ports.
503
504 Tout d'abord, il faut déclarer dans un fichier IDL (MesPorts.idl dans l'exemple) son ou ses 
505 ports :
506
507 ::
508
509   module Ports {
510     module Mes_Ports {
511       interface Mon_Type_De_Port : Ports::Data_Port {
512         boolean is_new_data_available();
513       };
514       interface Short_Mes_Ports : Mon_Type_De_Port {
515         void put(in short data);
516       };
517     };
518   };
519
520 Dans cet exemple on déclare un port : Short_Mes_Ports. Il s'agit d'un port qui permet 
521 d'envoyer un short, mais également qui peut être interrogé pour savoir si une nouvelle 
522 donnée est arrivée. En revanche la méthode get() n'est pas déclaré dans l'IDL (bien que 
523 ce soit possible) car elle uniquement destinée à être utilisé en local.
524
525 Il faut maintenant implémenter le type de port. Pour cela, il faut implémenter la fabrique 
526 et la partie uses et la partie provides du type de port.
527
528 Une fabrique de port est un objet qui implémente l'interface de la classe abstraite 
529 port_factory (voir la documentation Doxygen). La fabrique est appelée à chaque fois qu'un 
530 service ajoute un port dans le composant (uses ou provides). La fabrique est identifiée par
531 une chaîne de caractère qui l'identifie auprès du composant. L'enregistrement des fabriques 
532 doit se faire au plus tôt. C'est pourquoi les fabriques sont enregistrées dans le constructeur 
533 du composant.
534
535 La figure suivante montre l'enregistrement de la fabrique dans le composant ProducteurAdv :
536
537 ::
538
539   ProducteurAdv_i::ProducteurAdv_i(CORBA::ORB_ptr orb,
540                                    PortableServer::POA_ptr poa,
541                                    PortableServer::ObjectId * contId, 
542                                    const char * instanceName, 
543                                    const char * interfaceName) :
544     Superv_Component_i(orb, poa, contId, instanceName, interfaceName)
545   {
546     _thisObj = this;
547     _id = _poa->activate_object(_thisObj);
548
549     register_factory("MESPORTS", new mes_ports_factory());
550   }
551
552 Dans cet exemple, le nouveau type de port est identifié par la chaîne MESPORTS. Il faut 
553 noter qu'il est interdit d'utiliser le symbole << _ >> dans  le nom. En effet, il sert de 
554 séparateur entre le nom de la famille et le type du port dans la famille (Ex : MESPORTS_short).
555
556 Il reste à implémenter les ports. Pour chaque port défini dans l'IDL, il faut implémenter 
557 la partie uses port et la partie provides port. L'implémentation côté uses doit hériter de 
558 la classe uses_port. Du côté provides, il faut hériter de la classe provides_port.
559
560 Les classes uses_port et provides_port sont des classes abstraites. Elles proposent des 
561 méthodes qui permettent d'automatiser l'enregistrement et la gestion des ports. Dans la couche 
562 DSC_Basic, c'est le développeur du composant qui doit implémenter ces mécanismes tandis que 
563 dans la couche DSC_User c'est au développeur des ports de se charger de ces fonctionnalités.
564
565 Les méthodes sont les suivantes :
566
567 ::
568
569   Pour le côté uses : 
570
571   virtual const char * get_repository_id() = 0;
572
573   virtual void uses_port_changed(Engines::DSC::uses_port * new_uses_port,
574                                      const Engines::DSC::Message message) = 0;
575
576   Pour le côté provides :
577
578   virtual Ports::Port_ptr get_port_ref() = 0;
579
580   virtual void provides_port_changed(int connection_nbr,
581                                          const Engines::DSC::Message message) {};
582
583 Du côté uses, il y a tout d'abord la méthode get_repository_id(). Elle permet d'obtenir 
584 le typecode CORBA du port. Il s'agit de fournir la même information que le premier argument 
585 de add_uses_port de la couche Basic. La méthode uses_port_changed(…) permet au port d'être 
586 averti des nouvelle connexions avec des port provides et de gérer la liste des connexions.
587
588 Du côté provides, get_port_ref() permet d'obtenir une référence CORBA sur le servant. Enfin 
589 la méthode provides_port_changed(…) peut être surdéfini si le port provides utilise 
590 l'information provenant des connexions/déconnexions.
591
592 Dans l' exemple, le port provides est implémenté par la classe data_short_mes_ports_provides 
593 et  le port uses est implémenté par la classe data_short_mes_ports_uses.
594
595