]> SALOME platform Git repositories - modules/kernel.git/blob - src/DSC/DSC_User/Datastream/GenericPort.hxx
Salome HOME
CCAR: add trace file for DSC/CALCIUM calls
[modules/kernel.git] / src / DSC / DSC_User / Datastream / GenericPort.hxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  File   : GenericPort.hxx
23 //  Author : Eric Fayolle (EDF)
24 //  Module : KERNEL
25 // Modified by : $LastChangedBy$
26 // Date        : $LastChangedDate: 2007-02-28 15:26:32 +0100 (mer, 28 fév 2007) $
27 // Id          : $Id$
28 //
29 #ifndef _GENERIC_PORT_HXX_
30 #define _GENERIC_PORT_HXX_
31
32 #include "CorbaTypeManipulator.hxx"
33
34 // SALOME CORBA Exception
35 #include "Utils_CorbaException.hxx"
36 // SALOME C++   Exception
37 #include "Utils_SALOME_Exception.hxx"
38 #include "utilities.h"
39
40 #include <iostream>
41 #include <map>
42
43 // Inclusions pour l'affichage
44 #include <algorithm>
45 #include <iterator>
46
47 //#define MYDEBUG
48
49 // Classe GenericPort
50 // --------------------------------
51 //
52 // Definition: Implemente un port de type "data-stream"
53 // Cette implémentation gère tous les types de données définies par DataManipulator::type
54 // Ce port est soumis à une politique d'itération sur les identificateurs de données (DataId)
55 // Un identificateur de données est construit à partir d'un ou plusieurs paramètres de la méthode put
56 // tels que :  une date, une itération, un pas de temps ou une combinaison de ces paramètres.
57
58 template < typename DataManipulator, class COUPLING_POLICY >
59 class GenericPort : public COUPLING_POLICY  {
60 public:
61   // Type de données manipulés 
62   typedef typename DataManipulator::Type         DataType;
63   typedef typename DataManipulator::CorbaInType  CorbaInDataType;
64
65   GenericPort(); 
66   virtual ~GenericPort();
67
68   template <typename TimeType,typename TagType> void     put(CorbaInDataType data,  TimeType time, TagType tag);
69   template <typename TimeType,typename TagType> DataType get(TimeType time, TagType tag);
70   template <typename TimeType,typename TagType> DataType get(TimeType& ti, TimeType tf, TagType tag = 0);
71   template <typename TimeType,typename TagType> DataType next(TimeType &t, TagType  &tag );
72   void      close (PortableServer::POA_var poa, PortableServer::ObjectId_var id);
73   void wakeupWaiting();
74
75 private:
76
77   // Type identifiant une instance de donnee. Exemple (time,tag) 
78   typedef typename COUPLING_POLICY::DataId DataId;
79   typedef std::map< DataId, DataType>      DataTable;
80
81   // Stockage des donnees recues et non encore distribuées
82   DataTable storedDatas ;
83
84   // Indicateur que le destinataire attend une instance particuliere de données
85   bool     waitingForConvenientDataId;
86   // Indicateur que le destinataire attend n'importe qu'elle instance de données
87   bool     waitingForAnyDataId;
88
89   // Identificateur de la donné que le destinataire (propriétaire du port) attend
90   DataId   expectedDataId ;
91   // Sauvegarde du DataId courant pour la méthode next 
92   DataId   lastDataId;
93   bool     lastDataIdSet;
94   // Exclusion mutuelle d'acces a la table des données reçues
95   omni_mutex     storedDatas_mutex;
96   // Condition d'attente d'une instance (Le processus du Get attend la condition declaree par le processus Put)
97   omni_condition cond_instance;
98
99 };
100
101 template < typename DataManipulator, typename COUPLING_POLICY >
102 GenericPort<DataManipulator, COUPLING_POLICY >::GenericPort() :
103   cond_instance(& this->storedDatas_mutex),waitingForConvenientDataId(false),
104   waitingForAnyDataId(false),lastDataIdSet(false) {}
105
106 template < typename DataManipulator, typename COUPLING_POLICY>
107 GenericPort<DataManipulator, COUPLING_POLICY>::~GenericPort() {
108   typename DataTable::iterator it;
109   for (it=storedDatas.begin(); it!=storedDatas.end(); ++it) {
110 #ifdef MYDEBUG
111     std::cerr << "~GenericPort() : destruction de la donnnée associée au DataId :"<<  (*it).first << std::endl;
112 #endif
113     DataManipulator::delete_data( (*it).second );
114   }
115 }
116
117 template < typename DataManipulator, typename COUPLING_POLICY> void 
118 GenericPort<DataManipulator, COUPLING_POLICY>::close (PortableServer::POA_var poa, 
119                                                       PortableServer::ObjectId_var id) {
120   // Ferme le port en supprimant le servant
121   // La desactivation du servant du POA provoque sa suppression
122   poa->deactivate_object (id);
123 }
124
125 template < typename DataManipulator, typename COUPLING_POLICY> void
126 GenericPort<DataManipulator, COUPLING_POLICY>::wakeupWaiting()
127 {
128 #ifdef MYDEBUG
129   std::cout << "-------- wakeupWaiting ------------------" << std::endl;
130 #endif
131   storedDatas_mutex.lock();
132   if (waitingForAnyDataId || waitingForConvenientDataId) {
133 #ifdef MYDEBUG
134     std::cout << "-------- wakeupWaiting:signal --------" << std::endl;
135     std::cout << std::flush;
136 #endif
137     cond_instance.signal();
138    }
139   storedDatas_mutex.unlock();
140
141 }
142
143 /* Methode put_generique
144  *
145  * Stocke en memoire une instance de donnee (pointeur) que l'emetteur donne a l'intention du destinataire.
146  * Reveille le destinataire, si il y a lieu.
147  */
148 template < typename DataManipulator, typename COUPLING_POLICY>
149 template < typename TimeType,typename TagType>
150 void GenericPort<DataManipulator, COUPLING_POLICY>::put(CorbaInDataType dataParam, 
151                                                         TimeType time, 
152                                                         TagType  tag) {
153   fflush(stdout);
154   fflush(stderr);
155   try {
156 #ifdef MYDEBUG
157     // Affichage des donnees pour DEBUGging
158     std::cerr << "parametres emis: " << time << ", " << tag << std::endl;
159     DataManipulator::dump(dataParam);
160 #endif
161   
162     // L'intérêt des paramètres time et tag pour ce port est décidé dans la politique de couplage
163     // Il est possible de filtrer en prenant en compte uniquement un paramètre time/tag ou les deux
164     // Il est également possible de convertir les données recues ou bien de les dupliquer
165     // pour plusieurs  valeurs de time et/ou tag (d'où la notion de container dans la politique de couplage)
166     typedef typename COUPLING_POLICY::DataIdContainer DataIdContainer;  
167     typedef typename COUPLING_POLICY::DataId          DataId;
168
169     DataId          dataId(time,tag);
170     // Effectue les traitements spécifiques à la politique de couplage 
171     // pour construire une liste d'ids (par filtrage, conversion ...)
172     // DataIdContainer dataIds(dataId,*(static_cast<const COUPLING_POLICY *>(this)));   
173     DataIdContainer dataIds(dataId, *this);   
174
175     typename DataIdContainer::iterator dataIdIt = dataIds.begin();
176
177     bool expectedDataReceived = false;
178
179 #ifdef MYDEBUG
180     std::cout << "-------- Put : MARK 1 ------------------" << std::endl;
181 #endif
182     if ( dataIds.empty() ) return;
183 #ifdef MYDEBUG
184     std::cout << "-------- Put : MARK 1bis ------------------" << std::endl;
185 #endif
186
187     // Recupere les donnees venant de l'ORB et relâche les structures CORBA 
188     // qui n'auraient plus cours en sortie de méthode put
189     DataType data = DataManipulator::get_data(dataParam);
190
191
192     int nbOfIter = 0;
193
194 #ifdef MYDEBUG
195     std::cout << "-------- Put : MARK 2 ------ "<< (dataIdIt == dataIds.end()) << "------------" << std::endl;
196     std::cout << "-------- Put : MARK 2bis "<< (*dataIdIt) <<"------------------" << std::endl;
197 #endif
198     storedDatas_mutex.lock();
199
200     for (;dataIdIt != dataIds.end();++dataIdIt) {
201
202 #ifdef MYDEBUG
203       std::cout << "-------- Put : MARK 3 ------------------" << std::endl;
204 #endif
205       // Duplique l'instance de donnée pour les autres dataIds 
206       if (nbOfIter > 0) data = DataManipulator::clone(data);
207 #ifdef MYDEBUG
208       std::cout << "-------- Put : MARK 3bis -----"<< dataIdIt.operator*() <<"------------" << std::endl;
209 #endif
210     
211       DataId currentDataId=*dataIdIt;
212
213 #ifdef MYDEBUG
214       std::cerr << "processing dataId : "<< currentDataId << std::endl;
215
216       std::cout << "-------- Put : MARK 4 ------------------" << std::endl;
217 #endif
218  
219       // Ajoute l'instance de la donnee a sa place dans la table de données
220       // ou remplace une instance précédente si elle existe
221     
222       // Recherche la première clé telle quelle ne soit pas <  currentDataId
223       // pour celà l'opérateur de comparaison storedDatas.key_comp() est utilisé
224       // <=> premier emplacement où l'on pourrait insérer notre DataId
225       // <=> en général équivaux à (*wDataIt).first >= currentDataId
226       typename DataTable::iterator wDataIt = storedDatas.lower_bound(currentDataId);
227 #ifdef MYDEBUG
228       std::cout << "-------- Put : MARK 5 ------------------" << std::endl;
229 #endif
230
231       // On n'a pas trouvé de dataId supérieur au notre ou 
232       // on a trouvé une clé >  à cet Id          
233       if (wDataIt == storedDatas.end() || storedDatas.key_comp()(currentDataId,(*wDataIt).first) ) {
234 #ifdef MYDEBUG
235         std::cout << "-------- Put : MARK 6 ------------------" << std::endl;
236 #endif
237         // Ajoute la donnee dans la table
238         wDataIt = storedDatas.insert(wDataIt, make_pair (currentDataId, data));
239       } else  {
240         // Si on n'est pas en fin de liste et qu'il n'y a pas de relation d'ordre strict
241         // entre notre dataId et le DataId pointé c'est qu'ils sont identiques
242 #ifdef MYDEBUG
243         std::cout << "-------- Put : MARK 7 ------------------" << std::endl;
244 #endif
245         // Les données sont remplacées par les nouvelles valeurs
246         // lorsque que le dataId existe déjà
247         DataType old_data = (*wDataIt).second;
248         (*wDataIt).second = data;
249         // Detruit la vieille donnee
250         DataManipulator::delete_data (old_data);
251       }
252   
253 #ifdef MYDEBUG
254       std::cout << "-------- Put : MARK 8 ------------------" << std::endl;
255 #endif
256       // Compte le nombre de dataIds à traiter
257       ++nbOfIter;
258
259 #ifdef MYDEBUG
260       std::cout << "-------- Put : waitingForConvenientDataId : " << waitingForConvenientDataId <<"---" << std::endl;
261       std::cout << "-------- Put : waitingForAnyDataId : " << waitingForAnyDataId <<"---" << std::endl;
262       std::cout << "-------- Put : currentDataId  : " << currentDataId <<"---" << std::endl;
263       std::cout << "-------- Put : expectedDataId : " << expectedDataId <<"---" << std::endl;
264       std::cout << "-------- Put : MARK 9 ------------------" << std::endl;
265 #endif
266
267       // A simplifier mais :
268       // - pas possible de mettre des arguments optionnels à cause
269       //   du type itérator qui n'est pas connu (pas de possibilité de déclarer un static )
270       // - compliquer de créer une méthode sans les paramètres inutiles tout en réutilisant
271       //   la méthode initiale car cette dernière ne peut pas être déclarée virtuelle 
272       //   à cause de ses paramètres templates. Du coup, il faudrait aussi redéfinir la
273       //   méthode simplifiée dans les classes définissant une politique 
274       //   de couplage particulière ...
275       bool dummy1,dummy2; typename DataTable::iterator dummy3;
276       // Par construction, les valeurs de waitingForAnyDataId, waitingForConvenientDataId et de 
277       // expectedDataId ne peuvent pas être modifiées pendant le traitement de la boucle
278       // sur les dataIds (à cause du lock utilisé dans la méthode put et les méthodes get )
279       // rem : Utilisation de l'évaluation gauche droite du logical C or
280       if ( waitingForAnyDataId || 
281            ( waitingForConvenientDataId && 
282              isDataIdConveniant(storedDatas, expectedDataId, dummy1, dummy2, dummy3) ) 
283            ) {
284 #ifdef MYDEBUG
285         std::cout << "-------- Put : MARK 10 ------------------" << std::endl;
286 #endif
287         //Doit pouvoir réveiller le get ici (a vérifier)
288         expectedDataReceived = true;
289       }
290     }
291    
292     if (expectedDataReceived) {
293 #ifdef MYDEBUG
294       std::cout << "-------- Put : MARK 11 ------------------" << std::endl;
295 #endif
296       // si waitingForAnyDataId était positionné, c'est forcément lui qui a activer
297       // expectedDataReceived à true
298       if (waitingForAnyDataId) 
299         waitingForAnyDataId        = false;
300       else 
301         waitingForConvenientDataId = false;
302       // Reveille le thread du destinataire (stoppe son attente)
303       // Ne faudrait-il pas réveiller plutôt tous les threads ?
304       // Celui  réveillé ne correspond pas forcément à celui qui demande
305       // cet expectedDataReceived.
306       // Pb1 : cas d'un un get séquentiel et d'un get sur un dataId que l'on vient de recevoir.
307       // Si l'on reveille le mauvais thread, l'autre va attendre indéfiniment ! (sauf timeout)
308       // Pb2 : également si deux attentes de DataIds même différents car on n'en stocke qu'un !
309       // Conclusion : Pour l'instant on ne gère pas un service multithreadé qui effectue
310       // des lectures simultanées sur le même port !
311 #ifdef MYDEBUG
312       std::cerr << "-------- Put : new datas available ------------------" << std::endl;
313 #endif
314       fflush(stdout);fflush(stderr);
315       cond_instance.signal();
316     }
317 #ifdef MYDEBUG
318     std::cout << "-------- Put : MARK 12 ------------------" << std::endl;
319 #endif
320
321     // Deverouille l'acces a la table : On peut remonter l'appel au dessus de expected...
322     storedDatas_mutex.unlock();
323
324 #ifdef MYDEBUG
325     std::cout << "-------- Put : MARK 13 ------------------" << std::endl;
326 #endif
327     fflush(stdout);
328     fflush(stderr);
329
330   } // Catch les exceptions SALOME//C++ pour la transformer en une exception SALOME//CORBA  
331   catch ( const SALOME_Exception & ex ) {
332     // On évite de laisser un  mutex
333     storedDatas_mutex.unlock();
334     THROW_SALOME_CORBA_EXCEPTION(ex.what(), SALOME::INTERNAL_ERROR);
335   }
336
337 }
338
339
340 // Version du Get en 0 copy
341 // ( n'effectue pas de recopie de la donnée trouvée dans storedDatas )
342 // ( L'utilisateur devra être attentif à la politique de gestion de l'historique
343 //   spécifique au mode de couplage car il peut y avoir une suppression potentielle 
344 //   d'une donnée utilisée directement dans le code utilisateur )
345 //  Le code doit prendre connaissance du transfert de propriété ou non des données
346 //  auprès du mode de couplage choisi. 
347 template < typename DataManipulator, typename COUPLING_POLICY >
348 template < typename TimeType,typename TagType>
349 typename DataManipulator::Type 
350 GenericPort<DataManipulator, COUPLING_POLICY>::get(TimeType time, 
351                                                    TagType  tag)
352 // REM : Laisse passer toutes les exceptions
353 //       En particulier les SALOME_Exceptions qui viennent de la COUPLING_POLICY
354 //       Pour déclarer le throw avec l'exception spécifique il faut que je vérifie
355 //       qu'un setunexpeted est positionné sinon le C++ arrête tout par appel à terminate
356 {
357   typedef typename COUPLING_POLICY::DataId DataId;
358   // (Pointeur sur séquence) ou valeur..
359   DataType dataToTransmit ;
360   bool     isEqual, isBounded;
361   typedef typename DataManipulator::InnerType InnerType;
362
363 #ifdef MYDEBUG
364   std::cout << "-------- Get : MARK 1 ------------------" << std::endl;
365 #endif
366   expectedDataId   = DataId(time,tag);
367 #ifdef MYDEBUG
368   std::cout << "-------- Get : MARK 2 ------------------" << std::endl;
369 #endif
370  
371   typename DataTable::iterator wDataIt1;
372
373   try {
374     storedDatas_mutex.lock(); // Gérer les Exceptions ds le corps de la méthode
375   
376     while ( true ) {
377  
378       // Renvoie isEqual si le dataId attendu est trouvé dans storedDatas :
379       //   - l'itérateur wDataIt1 pointe alors sur ce dataId
380       // Renvoie isBounded si le dataId attendu n'est pas trouvé mais encadrable et 
381       // que la politique  gére ce cas de figure 
382       //   - l'itérateur wDataIt1 est tel que wDataIt1->first < wdataId < (wDataIt1+1)->first
383       // Méthode provenant de la COUPLING_POLICY
384       isDataIdConveniant(storedDatas,expectedDataId,isEqual,isBounded,wDataIt1);
385 #ifdef MYDEBUG
386       std::cout << "-------- Get : MARK 3 ------------------" << std::endl;
387 #endif
388
389       // L'ordre des différents tests est important
390       if ( isEqual ) {
391  
392 #ifdef MYDEBUG
393         std::cout << "-------- Get : MARK 4 ------------------" << std::endl;
394 #endif
395         // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM.
396         // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
397         // C'est EraseDataId qui choisi ou non de supprimer la donnée
398         // Du coup interaction potentielle entre le 0 copy et gestion de l'historique
399         dataToTransmit = (*wDataIt1).second; 
400
401 #ifdef MYDEBUG
402         std::cout << "-------- Get : MARK 5 ------------------" << std::endl;
403         std::cout << "-------- Get : Données trouvées à t : " << std::endl;
404         typename DataManipulator::InnerType const * const InIt1 = DataManipulator::getPointer(dataToTransmit);
405         size_t   N = DataManipulator::size(dataToTransmit);
406         std::copy(InIt1,        InIt1 + N,
407                   std::ostream_iterator< InnerType > (std::cout," "));
408         std::cout << std::endl;
409 #endif
410
411         // Décide de la suppression de certaines  instances de données 
412         // La donnée contenu dans la structure CORBA et son dataId sont désallouées
413         // Méthode provenant de la COUPLING_POLICY 
414         typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
415         processEraseDataId.apply(storedDatas,wDataIt1);
416 #ifdef MYDEBUG
417         std::cout << "-------- Get : MARK 6 ------------------" << std::endl;
418 #endif
419         break;
420
421       }
422 #ifdef MYDEBUG
423       std::cout << "-------- Get : MARK 7 ------------------" << std::endl;
424 #endif
425
426       //if (  isBounded() && COUPLING_POLICY::template needToProcessBoundedDataId() ) {
427       // Le DataId demandé n'est pas trouvé mais est encadré ET la politique de couplage
428       // implémente une méthode processBoundedDataId capable de générer les données à retourner
429       if (  isBounded ) {
430         // Pour être cohérent avec la politique du bloc précédent
431         // on stocke la paire (dataId,données interpolées ).
432         // CALCIUM ne stockait pas les données interpolées. 
433         // Cependant  comme les données sont censées être produites
434         // par ordre croissant de DataId, de nouvelles données ne devrait pas améliorer
435         // l'interpolation.
436 #ifdef MYDEBUG
437         std::cout << "-------- Get : MARK 8 ------------------" << std::endl;
438 #endif
439
440         typedef typename COUPLING_POLICY::template BoundedDataIdProcessor<DataManipulator> BDI;
441         BDI processBoundedDataId(*this);
442         //      typename COUPLING_POLICY::template BoundedDataIdProcessor<DataManipulator> processBoundedDataId(*this);
443         //si static BDIP::apply(dataToTransmit,expectedDataId,wDataIt1);
444         //ancienne version template processBoundedDataId<DataManipulator>(dataToTransmit,expectedDataId,wDataIt1);
445         //BDIP processBoundedDataId;
446         processBoundedDataId.apply(dataToTransmit,expectedDataId,wDataIt1);
447   
448         // Il ne peut pas y avoir déjà une clé expectedDataId dans storedDatas (utilisation de la notation [] )
449         // La nouvelle donnée produite est stockée, ce n'était pas le cas dans CALCIUM
450         // Cette opération n'a peut être pas un caractère générique.
451         // A déplacer en paramètre de la méthode précédente ? ou déléguer ce choix au mode de couplage ?
452         storedDatas[expectedDataId]=dataToTransmit;
453
454 #ifdef MYDEBUG
455         std::cout << "-------- Get : Données calculées à t : " << std::endl;
456         typename DataManipulator::InnerType const * const InIt1 = DataManipulator::getPointer(dataToTransmit);
457         size_t   N = DataManipulator::size(dataToTransmit);
458  
459         std::copy(InIt1,        InIt1 + N,
460                   std::ostream_iterator< InnerType > (std::cout," "));
461         std::cout << std::endl;
462         std::cout << "-------- Get : MARK 9 ------------------" << std::endl;
463 #endif
464
465         typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
466         processEraseDataId.apply(storedDatas,wDataIt1);
467    
468         break;
469       }
470   
471       // Délègue au mode de couplage la gestion d'une demande de donnée non disponible 
472       // si le port est deconnecté
473       typename COUPLING_POLICY::template DisconnectProcessor<DataManipulator> processDisconnect(*this);
474       if ( processDisconnect.apply(storedDatas, expectedDataId, wDataIt1) ) continue;
475     
476       // Réception bloquante sur le dataId demandé
477       // Si l'instance de donnée n'est pas trouvee
478 #ifdef MYDEBUG
479       std::cout << "-------- Get : MARK 10 ------------------" << std::endl;
480 #endif
481       //Positionné à faux dans la méthode put
482       waitingForConvenientDataId = true; 
483 #ifdef MYDEBUG
484       std::cout << "-------- Get : MARK 11 ------------------" << std::endl;
485      
486       // Ici on attend que la méthode put recoive la donnée 
487       std::cout << "-------- Get : waiting datas ------------------" << std::endl;
488 #endif
489       fflush(stdout);fflush(stderr);
490       cond_instance.wait();
491
492 #ifdef MYDEBUG
493       std::cout << "-------- Get : MARK 12 ------------------" << std::endl;
494 #endif
495     }
496
497   } catch (...) {
498     waitingForConvenientDataId = true;
499     storedDatas_mutex.unlock();
500     throw;
501   }
502
503   // Deverouille l'acces a la table
504   storedDatas_mutex.unlock();
505 #ifdef MYDEBUG
506   std::cout << "-------- Get : MARK 13 ------------------" << std::endl;
507 #endif
508
509   // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM
510   // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
511   // c'est eraseDataId qui choisi ou non de supprimer la donnée
512   // Du coup interaction potentielle entre le 0 copy et gestion des niveaux 
513   return dataToTransmit; 
514
515 }
516
517 template < typename DataManipulator, typename COUPLING_POLICY >
518 template < typename TimeType,typename TagType>
519 typename DataManipulator::Type 
520 GenericPort<DataManipulator, COUPLING_POLICY>::get(TimeType& ti,
521                                                    TimeType tf, 
522                                                    TagType  tag ) {
523   ti = COUPLING_POLICY::getEffectiveTime(ti,tf);
524   return get(ti,tag);
525 }
526
527
528 // Version du next en 0 copy
529 // ( n'effectue pas de recopie de la donnée trouvée dans storedDatas )
530 template < typename DataManipulator, typename COUPLING_POLICY >
531 template < typename TimeType,typename TagType>
532 typename DataManipulator::Type 
533 GenericPort<DataManipulator, COUPLING_POLICY>::next(TimeType &t,
534                                                     TagType  &tag ) {
535  
536   typedef  typename COUPLING_POLICY::DataId DataId;
537
538   DataType dataToTransmit;
539   DataId   dataId;
540
541   try {
542     storedDatas_mutex.lock();// Gérer les Exceptions ds le corps de la méthode
543
544 #ifdef MYDEBUG
545     std::cout << "-------- Next : MARK 1 ---lastDataIdSet ("<<lastDataIdSet<<")---------------" << std::endl;
546 #endif
547
548     typename DataTable::iterator wDataIt1;
549     wDataIt1 = storedDatas.end();
550
551     //Recherche le prochain dataId à renvoyer
552     // - lastDataIdset == true indique que lastDataId
553     // contient le dernier DataId renvoyé
554     // - lastDataIdset == false indique que l'on renverra
555     //   le premier dataId trouvé
556     // - upper_bound(lastDataId) situe le prochain DataId
557     // à renvoyer
558     // Rem : les données renvoyées ne sont effacées par eraseDataIds
559     //       si necessaire
560     if (lastDataIdSet) 
561       wDataIt1 = storedDatas.upper_bound(lastDataId);
562     else if ( !storedDatas.empty() ) {
563       lastDataIdSet = true;
564       wDataIt1      = storedDatas.begin();
565     }
566
567     typename COUPLING_POLICY::template DisconnectProcessor<DataManipulator> processDisconnect(*this);
568
569     while ( storedDatas.empty() || wDataIt1 == storedDatas.end() ) {
570
571       // Délègue au mode de couplage la gestion d'une demande de donnée non disponible 
572       // si le port est deconnecté
573       if ( processDisconnect.apply(storedDatas, lastDataId, wDataIt1) )  {
574         waitingForAnyDataId = false; break;
575       }
576   
577 #ifdef MYDEBUG
578       std::cout << "-------- Next : MARK 2 ------------------" << std::endl;
579 #endif
580       //Positionné à faux dans la méthode put
581       waitingForAnyDataId   = true;
582 #ifdef MYDEBUG
583       std::cout << "-------- Next : MARK 3 ------------------" << std::endl;
584       // Ici on attend que la méthode put recoive la donnée 
585       std::cout << "-------- Next : waiting datas ------------------" << std::endl;
586 #endif
587       fflush(stdout);fflush(stderr);
588       cond_instance.wait();
589
590       if (lastDataIdSet) {
591 #ifdef MYDEBUG
592         std::cout << "-------- Next : MARK 4 ------------------" << std::endl;
593 #endif
594         wDataIt1 = storedDatas.upper_bound(lastDataId);
595       } else  {
596 #ifdef MYDEBUG
597         std::cout << "-------- Next : MARK 5 ------------------" << std::endl;
598 #endif
599         lastDataIdSet = true;
600         wDataIt1      = storedDatas.begin();
601       }
602     }
603
604 #ifdef MYDEBUG
605     std::cout << "-------- Next : MARK 6 ------------------" << std::endl;
606 #endif
607
608     t   = getTime( (*wDataIt1).first );
609     tag = getTag ( (*wDataIt1).first );
610     dataToTransmit = (*wDataIt1).second;
611  
612 #ifdef MYDEBUG
613     std::cout << "-------- Next : MARK 7 ------------------" << std::endl;
614 #endif
615     lastDataId    = (*wDataIt1).first;
616
617     typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
618     processEraseDataId.apply(storedDatas, wDataIt1);
619
620 #ifdef MYDEBUG
621     std::cout << "-------- Next : MARK 8 ------------------" << std::endl;   
622 #endif
623   } catch (...) {
624 #ifdef MYDEBUG
625     std::cout << "-------- Next : MARK 8bis ------------------" << std::endl;
626 #endif
627     waitingForAnyDataId = false;
628     storedDatas_mutex.unlock();
629     throw;
630   }
631   storedDatas_mutex.unlock();
632   
633 #ifdef MYDEBUG
634   std::cout << "-------- Next : MARK 9 ------------------" << std::endl;
635 #endif
636
637   // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM
638   // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
639   // c'est eraseDataId qui choisi ou non de supprimer la donnée
640   // Du coup interaction potentielle entre le 0 copy et gestion des niveaux 
641   return dataToTransmit; 
642
643 };
644
645 #endif