Salome HOME
CCAR: remove debug prints from the standard trace and put these prints
[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       MESSAGE("-------- Put : new datas available ------------------");
312       fflush(stdout);fflush(stderr);
313       cond_instance.signal();
314     }
315 #ifdef MYDEBUG
316     std::cout << "-------- Put : MARK 12 ------------------" << std::endl;
317 #endif
318
319     // Deverouille l'acces a la table : On peut remonter l'appel au dessus de expected...
320     storedDatas_mutex.unlock();
321
322 #ifdef MYDEBUG
323     std::cout << "-------- Put : MARK 13 ------------------" << std::endl;
324 #endif
325     fflush(stdout);
326     fflush(stderr);
327
328   } // Catch les exceptions SALOME//C++ pour la transformer en une exception SALOME//CORBA  
329   catch ( const SALOME_Exception & ex ) {
330     // On évite de laisser un  mutex
331     storedDatas_mutex.unlock();
332     THROW_SALOME_CORBA_EXCEPTION(ex.what(), SALOME::INTERNAL_ERROR);
333   }
334
335 }
336
337
338 // Version du Get en 0 copy
339 // ( n'effectue pas de recopie de la donnée trouvée dans storedDatas )
340 // ( L'utilisateur devra être attentif à la politique de gestion de l'historique
341 //   spécifique au mode de couplage car il peut y avoir une suppression potentielle 
342 //   d'une donnée utilisée directement dans le code utilisateur )
343 //  Le code doit prendre connaissance du transfert de propriété ou non des données
344 //  auprès du mode de couplage choisi. 
345 template < typename DataManipulator, typename COUPLING_POLICY >
346 template < typename TimeType,typename TagType>
347 typename DataManipulator::Type 
348 GenericPort<DataManipulator, COUPLING_POLICY>::get(TimeType time, 
349                                                    TagType  tag)
350 // REM : Laisse passer toutes les exceptions
351 //       En particulier les SALOME_Exceptions qui viennent de la COUPLING_POLICY
352 //       Pour déclarer le throw avec l'exception spécifique il faut que je vérifie
353 //       qu'un setunexpeted est positionné sinon le C++ arrête tout par appel à terminate
354 {
355   typedef typename COUPLING_POLICY::DataId DataId;
356   // (Pointeur sur séquence) ou valeur..
357   DataType dataToTransmit ;
358   bool     isEqual, isBounded;
359   typedef typename DataManipulator::InnerType InnerType;
360
361 #ifdef MYDEBUG
362   std::cout << "-------- Get : MARK 1 ------------------" << std::endl;
363 #endif
364   expectedDataId   = DataId(time,tag);
365 #ifdef MYDEBUG
366   std::cout << "-------- Get : MARK 2 ------------------" << std::endl;
367 #endif
368  
369   typename DataTable::iterator wDataIt1;
370
371   try {
372     storedDatas_mutex.lock(); // Gérer les Exceptions ds le corps de la méthode
373   
374     while ( true ) {
375  
376       // Renvoie isEqual si le dataId attendu est trouvé dans storedDatas :
377       //   - l'itérateur wDataIt1 pointe alors sur ce dataId
378       // Renvoie isBounded si le dataId attendu n'est pas trouvé mais encadrable et 
379       // que la politique  gére ce cas de figure 
380       //   - l'itérateur wDataIt1 est tel que wDataIt1->first < wdataId < (wDataIt1+1)->first
381       // Méthode provenant de la COUPLING_POLICY
382       isDataIdConveniant(storedDatas,expectedDataId,isEqual,isBounded,wDataIt1);
383 #ifdef MYDEBUG
384       std::cout << "-------- Get : MARK 3 ------------------" << std::endl;
385 #endif
386
387       // L'ordre des différents tests est important
388       if ( isEqual ) {
389  
390 #ifdef MYDEBUG
391         std::cout << "-------- Get : MARK 4 ------------------" << std::endl;
392 #endif
393         // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM.
394         // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
395         // C'est EraseDataId qui choisi ou non de supprimer la donnée
396         // Du coup interaction potentielle entre le 0 copy et gestion de l'historique
397         dataToTransmit = (*wDataIt1).second; 
398
399 #ifdef MYDEBUG
400         std::cout << "-------- Get : MARK 5 ------------------" << std::endl;
401         std::cout << "-------- Get : Données trouvées à t : " << std::endl;
402         typename DataManipulator::InnerType const * const InIt1 = DataManipulator::getPointer(dataToTransmit);
403         size_t   N = DataManipulator::size(dataToTransmit);
404         std::copy(InIt1,        InIt1 + N,
405                   std::ostream_iterator< InnerType > (std::cout," "));
406         std::cout << std::endl;
407 #endif
408
409         // Décide de la suppression de certaines  instances de données 
410         // La donnée contenu dans la structure CORBA et son dataId sont désallouées
411         // Méthode provenant de la COUPLING_POLICY 
412         typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
413         processEraseDataId.apply(storedDatas,wDataIt1);
414 #ifdef MYDEBUG
415         std::cout << "-------- Get : MARK 6 ------------------" << std::endl;
416 #endif
417         break;
418
419       }
420 #ifdef MYDEBUG
421       std::cout << "-------- Get : MARK 7 ------------------" << std::endl;
422 #endif
423
424       //if (  isBounded() && COUPLING_POLICY::template needToProcessBoundedDataId() ) {
425       // Le DataId demandé n'est pas trouvé mais est encadré ET la politique de couplage
426       // implémente une méthode processBoundedDataId capable de générer les données à retourner
427       if (  isBounded ) {
428         // Pour être cohérent avec la politique du bloc précédent
429         // on stocke la paire (dataId,données interpolées ).
430         // CALCIUM ne stockait pas les données interpolées. 
431         // Cependant  comme les données sont censées être produites
432         // par ordre croissant de DataId, de nouvelles données ne devrait pas améliorer
433         // l'interpolation.
434 #ifdef MYDEBUG
435         std::cout << "-------- Get : MARK 8 ------------------" << std::endl;
436 #endif
437
438         typedef typename COUPLING_POLICY::template BoundedDataIdProcessor<DataManipulator> BDI;
439         BDI processBoundedDataId(*this);
440         //      typename COUPLING_POLICY::template BoundedDataIdProcessor<DataManipulator> processBoundedDataId(*this);
441         //si static BDIP::apply(dataToTransmit,expectedDataId,wDataIt1);
442         //ancienne version template processBoundedDataId<DataManipulator>(dataToTransmit,expectedDataId,wDataIt1);
443         //BDIP processBoundedDataId;
444         processBoundedDataId.apply(dataToTransmit,expectedDataId,wDataIt1);
445   
446         // Il ne peut pas y avoir déjà une clé expectedDataId dans storedDatas (utilisation de la notation [] )
447         // La nouvelle donnée produite est stockée, ce n'était pas le cas dans CALCIUM
448         // Cette opération n'a peut être pas un caractère générique.
449         // A déplacer en paramètre de la méthode précédente ? ou déléguer ce choix au mode de couplage ?
450         storedDatas[expectedDataId]=dataToTransmit;
451
452 #ifdef MYDEBUG
453         std::cout << "-------- Get : Données calculées à t : " << std::endl;
454         typename DataManipulator::InnerType const * const InIt1 = DataManipulator::getPointer(dataToTransmit);
455         size_t   N = DataManipulator::size(dataToTransmit);
456  
457         std::copy(InIt1,        InIt1 + N,
458                   std::ostream_iterator< InnerType > (std::cout," "));
459         std::cout << std::endl;
460         std::cout << "-------- Get : MARK 9 ------------------" << std::endl;
461 #endif
462
463         typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
464         processEraseDataId.apply(storedDatas,wDataIt1);
465    
466         break;
467       }
468   
469       // Délègue au mode de couplage la gestion d'une demande de donnée non disponible 
470       // si le port est deconnecté
471       typename COUPLING_POLICY::template DisconnectProcessor<DataManipulator> processDisconnect(*this);
472       if ( processDisconnect.apply(storedDatas, expectedDataId, wDataIt1) ) continue;
473     
474       // Réception bloquante sur le dataId demandé
475       // Si l'instance de donnée n'est pas trouvee
476 #ifdef MYDEBUG
477       std::cout << "-------- Get : MARK 10 ------------------" << std::endl;
478 #endif
479       //Positionné à faux dans la méthode put
480       waitingForConvenientDataId = true; 
481 #ifdef MYDEBUG
482       std::cout << "-------- Get : MARK 11 ------------------" << std::endl;
483      
484       // Ici on attend que la méthode put recoive la donnée 
485       std::cout << "-------- Get : waiting datas ------------------" << std::endl;
486 #endif
487       fflush(stdout);fflush(stderr);
488       cond_instance.wait();
489
490 #ifdef MYDEBUG
491       std::cout << "-------- Get : MARK 12 ------------------" << std::endl;
492 #endif
493     }
494
495   } catch (...) {
496     waitingForConvenientDataId = true;
497     storedDatas_mutex.unlock();
498     throw;
499   }
500
501   // Deverouille l'acces a la table
502   storedDatas_mutex.unlock();
503 #ifdef MYDEBUG
504   std::cout << "-------- Get : MARK 13 ------------------" << std::endl;
505 #endif
506
507   // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM
508   // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
509   // c'est eraseDataId qui choisi ou non de supprimer la donnée
510   // Du coup interaction potentielle entre le 0 copy et gestion des niveaux 
511   return dataToTransmit; 
512
513 }
514
515 template < typename DataManipulator, typename COUPLING_POLICY >
516 template < typename TimeType,typename TagType>
517 typename DataManipulator::Type 
518 GenericPort<DataManipulator, COUPLING_POLICY>::get(TimeType ti,
519                                                    TimeType tf, 
520                                                    TagType  tag ) {
521   TimeType t = COUPLING_POLICY::getEffectiveTime(ti,tf);
522   return get(t,tag);
523 }
524
525
526 // Version du next en 0 copy
527 // ( n'effectue pas de recopie de la donnée trouvée dans storedDatas )
528 template < typename DataManipulator, typename COUPLING_POLICY >
529 template < typename TimeType,typename TagType>
530 typename DataManipulator::Type 
531 GenericPort<DataManipulator, COUPLING_POLICY>::next(TimeType &t,
532                                                     TagType  &tag ) {
533  
534   typedef  typename COUPLING_POLICY::DataId DataId;
535
536   DataType dataToTransmit;
537   DataId   dataId;
538
539   try {
540     storedDatas_mutex.lock();// Gérer les Exceptions ds le corps de la méthode
541
542 #ifdef MYDEBUG
543     std::cout << "-------- Next : MARK 1 ---lastDataIdSet ("<<lastDataIdSet<<")---------------" << std::endl;
544 #endif
545
546     typename DataTable::iterator wDataIt1;
547     wDataIt1 = storedDatas.end();
548
549     //Recherche le prochain dataId à renvoyer
550     // - lastDataIdset == true indique que lastDataId
551     // contient le dernier DataId renvoyé
552     // - lastDataIdset == false indique que l'on renverra
553     //   le premier dataId trouvé
554     // - upper_bound(lastDataId) situe le prochain DataId
555     // à renvoyer
556     // Rem : les données renvoyées ne sont effacées par eraseDataIds
557     //       si necessaire
558     if (lastDataIdSet) 
559       wDataIt1 = storedDatas.upper_bound(lastDataId);
560     else if ( !storedDatas.empty() ) {
561       lastDataIdSet = true;
562       wDataIt1      = storedDatas.begin();
563     }
564
565     typename COUPLING_POLICY::template DisconnectProcessor<DataManipulator> processDisconnect(*this);
566
567     while ( storedDatas.empty() || wDataIt1 == storedDatas.end() ) {
568
569       // Délègue au mode de couplage la gestion d'une demande de donnée non disponible 
570       // si le port est deconnecté
571       if ( processDisconnect.apply(storedDatas, lastDataId, wDataIt1) )  {
572         waitingForAnyDataId = false; break;
573       }
574   
575 #ifdef MYDEBUG
576       std::cout << "-------- Next : MARK 2 ------------------" << std::endl;
577 #endif
578       //Positionné à faux dans la méthode put
579       waitingForAnyDataId   = true;
580 #ifdef MYDEBUG
581       std::cout << "-------- Next : MARK 3 ------------------" << std::endl;
582       // Ici on attend que la méthode put recoive la donnée 
583       std::cout << "-------- Next : waiting datas ------------------" << std::endl;
584 #endif
585       fflush(stdout);fflush(stderr);
586       cond_instance.wait();
587
588       if (lastDataIdSet) {
589 #ifdef MYDEBUG
590         std::cout << "-------- Next : MARK 4 ------------------" << std::endl;
591 #endif
592         wDataIt1 = storedDatas.upper_bound(lastDataId);
593       } else  {
594 #ifdef MYDEBUG
595         std::cout << "-------- Next : MARK 5 ------------------" << std::endl;
596 #endif
597         lastDataIdSet = true;
598         wDataIt1      = storedDatas.begin();
599       }
600     }
601
602 #ifdef MYDEBUG
603     std::cout << "-------- Next : MARK 6 ------------------" << std::endl;
604 #endif
605
606     t   = getTime( (*wDataIt1).first );
607     tag = getTag ( (*wDataIt1).first );
608     dataToTransmit = (*wDataIt1).second;
609  
610 #ifdef MYDEBUG
611     std::cout << "-------- Next : MARK 7 ------------------" << std::endl;
612 #endif
613     lastDataId    = (*wDataIt1).first;
614
615     typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
616     processEraseDataId.apply(storedDatas, wDataIt1);
617
618 #ifdef MYDEBUG
619     std::cout << "-------- Next : MARK 8 ------------------" << std::endl;   
620 #endif
621   } catch (...) {
622 #ifdef MYDEBUG
623     std::cout << "-------- Next : MARK 8bis ------------------" << std::endl;
624 #endif
625     waitingForAnyDataId = false;
626     storedDatas_mutex.unlock();
627     throw;
628   }
629   storedDatas_mutex.unlock();
630   
631 #ifdef MYDEBUG
632   std::cout << "-------- Next : MARK 9 ------------------" << std::endl;
633 #endif
634
635   // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM
636   // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
637   // c'est eraseDataId qui choisi ou non de supprimer la donnée
638   // Du coup interaction potentielle entre le 0 copy et gestion des niveaux 
639   return dataToTransmit; 
640
641 };
642
643 #endif