1 // Copyright (C) 2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License.
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // File : GenericPort.hxx
23 // Author : Eric Fayolle (EDF)
25 // Modified by : $LastChangedBy$
26 // Date : $LastChangedDate: 2007-02-28 15:26:32 +0100 (mer, 28 fév 2007) $
29 #ifndef _GENERIC_PORT_HXX_
30 #define _GENERIC_PORT_HXX_
32 #include "CorbaTypeManipulator.hxx"
34 // SALOME CORBA Exception
35 #include "Utils_CorbaException.hxx"
36 // SALOME C++ Exception
37 #include "Utils_SALOME_Exception.hxx"
42 // Inclusions pour l'affichage
47 // --------------------------------
49 // Definition: Implemente un port de type "data-stream"
50 // Cette implémentation gère tous les types de données définies par DataManipulator::type
51 // Ce port est soumis à une politique d'itération sur les identificateurs de données (DataId)
52 // Un identificateur de données est construit à partir d'un ou plusieurs paramètres de la méthode put
53 // tels que : une date, une itération, un pas de temps ou une combinaison de ces paramètres.
55 template < typename DataManipulator, class COUPLING_POLICY >
56 class GenericPort : public COUPLING_POLICY {
58 // Type de données manipulés
59 typedef typename DataManipulator::Type DataType;
60 typedef typename DataManipulator::CorbaInType CorbaInDataType;
63 virtual ~GenericPort();
65 template <typename TimeType,typename TagType> void put(CorbaInDataType data, TimeType time, TagType tag);
66 template <typename TimeType,typename TagType> DataType get(TimeType time, TagType tag);
67 template <typename TimeType,typename TagType> DataType get(TimeType ti, TimeType tf, TagType tag = 0);
68 template <typename TimeType,typename TagType> DataType next(TimeType &t, TagType &tag );
69 void close (PortableServer::POA_var poa, PortableServer::ObjectId_var id);
74 // Type identifiant une instance de donnee. Exemple (time,tag)
75 typedef typename COUPLING_POLICY::DataId DataId;
76 typedef std::map< DataId, DataType> DataTable;
78 // Stockage des donnees recues et non encore distribuées
79 DataTable storedDatas ;
81 // Indicateur que le destinataire attend une instance particuliere de données
82 bool waitingForConvenientDataId;
83 // Indicateur que le destinataire attend n'importe qu'elle instance de données
84 bool waitingForAnyDataId;
86 // Identificateur de la donné que le destinataire (propriétaire du port) attend
87 DataId expectedDataId ;
88 // Sauvegarde du DataId courant pour la méthode next
91 // Exclusion mutuelle d'acces a la table des données reçues
92 omni_mutex storedDatas_mutex;
93 // Condition d'attente d'une instance (Le processus du Get attend la condition declaree par le processus Put)
94 omni_condition cond_instance;
98 template < typename DataManipulator, typename COUPLING_POLICY >
99 GenericPort<DataManipulator, COUPLING_POLICY >::GenericPort() :
100 cond_instance(& this->storedDatas_mutex),waitingForConvenientDataId(false),
101 waitingForAnyDataId(false),lastDataIdSet(false) {}
103 template < typename DataManipulator, typename COUPLING_POLICY>
104 GenericPort<DataManipulator, COUPLING_POLICY>::~GenericPort() {
105 typename DataTable::iterator it;
106 // for (it=storedDatas.begin(); it!=storedDatas.end(); ++it) {
107 // std::cout << "~GenericPort() : destruction de la donnnée associée au DataId :"<< (*it).first << std::endl;
108 // DataManipulator::delete_data( (*it).second );
112 template < typename DataManipulator, typename COUPLING_POLICY> void
113 GenericPort<DataManipulator, COUPLING_POLICY>::close (PortableServer::POA_var poa,
114 PortableServer::ObjectId_var id) {
115 // Ferme le port en supprimant le servant
116 // La desactivation du servant du POA provoque sa suppression
117 poa->deactivate_object (id);
120 template < typename DataManipulator, typename COUPLING_POLICY> void
121 GenericPort<DataManipulator, COUPLING_POLICY>::wakeupWaiting()
123 std::cout << "-------- wakeupWaiting ------------------" << std::endl;
124 if (waitingForAnyDataId || waitingForConvenientDataId)
126 std::cout << "-------- wakeupWaiting:signal --------" << std::endl;
127 std::cout << std::flush;
128 cond_instance.signal();
132 /* Methode put_generique
134 * Stocke en memoire une instance de donnee (pointeur) que l'emetteur donne a l'intention du destinataire.
135 * Reveille le destinataire, si il y a lieu.
137 template < typename DataManipulator, typename COUPLING_POLICY>
138 template < typename TimeType,typename TagType>
139 void GenericPort<DataManipulator, COUPLING_POLICY>::put(CorbaInDataType dataParam,
145 // Affichage des donnees pour DEBUGging
146 cerr << "parametres emis: " << time << ", " << tag << endl;
147 DataManipulator::dump(dataParam);
149 // L'intérêt des paramètres time et tag pour ce port est décidé dans la politique de couplage
150 // Il est possible de filtrer en prenant en compte uniquement un paramètre time/tag ou les deux
151 // Il est également possible de convertir les données recues ou bien de les dupliquer
152 // pour plusieurs valeurs de time et/ou tag (d'où la notion de container dans la politique de couplage)
153 typedef typename COUPLING_POLICY::DataIdContainer DataIdContainer;
154 typedef typename COUPLING_POLICY::DataId DataId;
156 DataId dataId(time,tag);
157 // Effectue les traitements spécifiques à la politique de couplage
158 // pour construire une liste d'ids (par filtrage, conversion ...)
159 // DataIdContainer dataIds(dataId,*(static_cast<const COUPLING_POLICY *>(this)));
160 DataIdContainer dataIds(dataId, *this);
162 typename DataIdContainer::iterator dataIdIt = dataIds.begin();
164 bool expectedDataReceived = false;
166 std::cout << "-------- Put : MARK 1 ------------------" << std::endl;
167 if ( dataIds.empty() ) return;
168 std::cout << "-------- Put : MARK 1bis ------------------" << std::endl;
170 // Recupere les donnees venant de l'ORB et relâche les structures CORBA
171 // qui n'auraient plus cours en sortie de méthode put
172 DataType data = DataManipulator::get_data(dataParam);
177 std::cout << "-------- Put : MARK 2 ------ "<< (dataIdIt == dataIds.end()) << "------------" << std::endl;
178 std::cout << "-------- Put : MARK 2bis "<< (*dataIdIt) <<"------------------" << std::endl;
179 storedDatas_mutex.lock();
181 for (;dataIdIt != dataIds.end();++dataIdIt) {
183 std::cout << "-------- Put : MARK 3 ------------------" << std::endl;
184 // Duplique l'instance de donnée pour les autres dataIds
185 if (nbOfIter > 0) data = DataManipulator::clone(data);
186 std::cout << "-------- Put : MARK 3bis -----"<< dataIdIt.operator*() <<"------------" << std::endl;
188 DataId currentDataId=*dataIdIt;
190 std::cerr << "processing dataId : "<< currentDataId << std::endl;
192 std::cout << "-------- Put : MARK 4 ------------------" << std::endl;
194 // Ajoute l'instance de la donnee a sa place dans la table de données
195 // ou remplace une instance précédente si elle existe
197 // Recherche la première clé telle quelle ne soit pas < currentDataId
198 // pour celà l'opérateur de comparaison storedDatas.key_comp() est utilisé
199 // <=> premier emplacement où l'on pourrait insérer notre DataId
200 // <=> en général équivaux à (*wDataIt).first >= currentDataId
201 typename DataTable::iterator wDataIt = storedDatas.lower_bound(currentDataId);
202 std::cout << "-------- Put : MARK 5 ------------------" << std::endl;
204 // On n'a pas trouvé de dataId supérieur au notre ou
205 // on a trouvé une clé > à cet Id
206 if (wDataIt == storedDatas.end() || storedDatas.key_comp()(currentDataId,(*wDataIt).first) ) {
207 std::cout << "-------- Put : MARK 6 ------------------" << std::endl;
208 // Ajoute la donnee dans la table
209 wDataIt = storedDatas.insert(wDataIt, make_pair (currentDataId, data));
211 // Si on n'est pas en fin de liste et qu'il n'y a pas de relation d'ordre strict
212 // entre notre dataId et le DataId pointé c'est qu'ils sont identiques
213 std::cout << "-------- Put : MARK 7 ------------------" << std::endl;
214 // Les données sont remplacées par les nouvelles valeurs
215 // lorsque que le dataId existe déjà
216 DataType old_data = (*wDataIt).second;
217 (*wDataIt).second = data;
218 // Detruit la vieille donnee
219 DataManipulator::delete_data (old_data);
222 std::cout << "-------- Put : MARK 8 ------------------" << std::endl;
223 // Compte le nombre de dataIds à traiter
226 std::cout << "-------- Put : waitingForConvenientDataId : " << waitingForConvenientDataId <<"---" << std::endl;
227 std::cout << "-------- Put : waitingForAnyDataId : " << waitingForAnyDataId <<"---" << std::endl;
228 std::cout << "-------- Put : currentDataId : " << currentDataId <<"---" << std::endl;
229 std::cout << "-------- Put : expectedDataId : " << expectedDataId <<"---" << std::endl;
230 std::cout << "-------- Put : MARK 9 ------------------" << std::endl;
232 // A simplifier mais :
233 // - pas possible de mettre des arguments optionnels à cause
234 // du type itérator qui n'est pas connu (pas de possibilité de déclarer un static )
235 // - compliquer de créer une méthode sans les paramètres inutiles tout en réutilisant
236 // la méthode initiale car cette dernière ne peut pas être déclarée virtuelle
237 // à cause de ses paramètres templates. Du coup, il faudrait aussi redéfinir la
238 // méthode simplifiée dans les classes définissant une politique
239 // de couplage particulière ...
240 bool dummy1,dummy2; typename DataTable::iterator dummy3;
241 // Par construction, les valeurs de waitingForAnyDataId, waitingForConvenientDataId et de
242 // expectedDataId ne peuvent pas être modifiées pendant le traitement de la boucle
243 // sur les dataIds (à cause du lock utilisé dans la méthode put et les méthodes get )
244 // rem : Utilisation de l'évaluation gauche droite su logical C or
245 if ( waitingForAnyDataId ||
246 ( waitingForConvenientDataId &&
247 isDataIdConveniant(storedDatas, expectedDataId, dummy1, dummy2, dummy3) )
249 std::cout << "-------- Put : MARK 10 ------------------" << std::endl;
250 //Doit pouvoir réveiller le get ici (a vérifier)
251 expectedDataReceived = true;
255 if (expectedDataReceived) {
256 std::cout << "-------- Put : MARK 11 ------------------" << std::endl;
257 // si waitingForAnyDataId était positionné, c'est forcément lui qui a activer
258 // expectedDataReceived à true
259 if (waitingForAnyDataId)
260 waitingForAnyDataId = false;
262 waitingForConvenientDataId = false;
263 // Reveille le thread du destinataire (stoppe son attente)
264 // Ne faudrait-il pas réveiller plutôt tous les threads ?
265 // Celui réveillé ne correspond pas forcément à celui qui demande
266 // cet expectedDataReceived.
267 // Pb1 : cas d'un un get séquentiel et d'un get sur un dataId que l'on vient de recevoir.
268 // Si l'on reveille le mauvais thread, l'autre va attendre indéfiniment ! (sauf timeout)
269 // Pb2 : également si deux attentes de DataIds même différents car on n'en stocke qu'un !
270 // Conclusion : Pour l'instant on ne gère pas un service multithreadé qui effectue
271 // des lectures simultanées sur le même port !
272 std::cout << "-------- Put : new datas available ------------------" << std::endl;
273 fflush(stdout);fflush(stderr);
274 cond_instance.signal();
276 std::cout << "-------- Put : MARK 12 ------------------" << std::endl;
278 // Deverouille l'acces a la table : On peut remonter l'appel au dessus de expected...
279 storedDatas_mutex.unlock();
281 std::cout << "-------- Put : MARK 13 ------------------" << std::endl;
285 } // Catch les exceptions SALOME//C++ pour la transformer en une exception SALOME//CORBA
286 catch ( const SALOME_Exception & ex ) {
287 // On évite de laisser un mutex
288 storedDatas_mutex.unlock();
291 THROW_SALOME_CORBA_EXCEPTION(ex.what(), SALOME::INTERNAL_ERROR);
297 // Version du Get en 0 copy
298 // ( n'effectue pas de recopie de la donnée trouvée dans storedDatas )
299 // ( L'utilisateur devra être attentif à la politique de gestion de l'historique
300 // spécifique au mode de couplage car il peut y avoir une suppression potentielle
301 // d'une donnée utilisée directement dans le code utilisateur )
302 // Le code doit prendre connaissance du transfert de propriété ou non des données
303 // auprès du mode de couplage choisi.
304 template < typename DataManipulator, typename COUPLING_POLICY >
305 template < typename TimeType,typename TagType>
306 typename DataManipulator::Type
307 GenericPort<DataManipulator, COUPLING_POLICY>::get(TimeType time,
309 // REM : Laisse passer toutes les exceptions
310 // En particulier les SALOME_Exceptions qui viennent de la COUPLING_POLICY
311 // Pour déclarer le throw avec l'exception spécifique il faut que je vérifie
312 // qu'un setunexpeted est positionné sinon le C++ arrête tout par appel à terminate
314 typedef typename COUPLING_POLICY::DataId DataId;
315 // (Pointeur sur séquence) ou valeur..
316 DataType dataToTransmit ;
317 bool isEqual, isBounded;
318 typedef typename DataManipulator::InnerType InnerType;
320 std::cout << "-------- Get : MARK 1 ------------------" << std::endl;
321 expectedDataId = DataId(time,tag);
322 std::cout << "-------- Get : MARK 2 ------------------" << std::endl;
324 typename DataTable::iterator wDataIt1;
327 storedDatas_mutex.lock(); // Gérer les Exceptions ds le corps de la méthode
331 // Renvoie isEqual si le dataId attendu est trouvé dans storedDatas :
332 // - l'itérateur wDataIt1 pointe alors sur ce dataId
333 // Renvoie isBounded si le dataId attendu n'est pas trouvé mais encadrable et
334 // que la politique gére ce cas de figure
335 // - l'itérateur wDataIt1 est tel que wDataIt1->first < wdataId < (wDataIt1+1)->first
336 // Méthode provenant de la COUPLING_POLICY
337 isDataIdConveniant(storedDatas,expectedDataId,isEqual,isBounded,wDataIt1);
338 std::cout << "-------- Get : MARK 3 ------------------" << std::endl;
340 // L'ordre des différents tests est important
343 std::cout << "-------- Get : MARK 4 ------------------" << std::endl;
344 // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM.
345 // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
346 // C'est EraseDataId qui choisi ou non de supprimer la donnée
347 // Du coup interaction potentielle entre le 0 copy et gestion de l'historique
348 dataToTransmit = (*wDataIt1).second;
350 std::cout << "-------- Get : MARK 5 ------------------" << std::endl;
351 std::cout << "-------- Get : Données trouvées à t : " << std::endl;
352 typename DataManipulator::InnerType const * const InIt1 = DataManipulator::getPointer(dataToTransmit);
353 size_t N = DataManipulator::size(dataToTransmit);
354 std::copy(InIt1, InIt1 + N,
355 std::ostream_iterator< InnerType > (std::cout," "));
356 std::cout << std::endl;
358 // Décide de la suppression de certaines instances de données
359 // La donnée contenu dans la structure CORBA et son dataId sont désallouées
360 // Méthode provenant de la COUPLING_POLICY
361 typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
362 processEraseDataId.apply(storedDatas,wDataIt1);
363 std::cout << "-------- Get : MARK 6 ------------------" << std::endl;
367 std::cout << "-------- Get : MARK 7 ------------------" << std::endl;
369 //if ( isBounded() && COUPLING_POLICY::template needToProcessBoundedDataId() ) {
370 // Le DataId demandé n'est pas trouvé mais est encadré ET la politique de couplage
371 // implémente une méthode processBoundedDataId capable de générer les données à retourner
373 // Pour être cohérent avec la politique du bloc précédent
374 // on stocke la paire (dataId,données interpolées ).
375 // CALCIUM ne stockait pas les données interpolées.
376 // Cependant comme les données sont censées être produites
377 // par ordre croissant de DataId, de nouvelles données ne devrait pas améliorer
379 // Les données calciulées sont donc stockées dans storedDatas.
380 // La propriété des données N'EST PAS transférée à l'utilisateur en mode CALCIUM.
381 std::cout << "-------- Get : MARK 8 ------------------" << std::endl;
383 typename COUPLING_POLICY::template BoundedDataIdProcessor<DataManipulator> processBoundedDataId(*this);
384 //si static BDIP::apply(dataToTransmit,expectedDataId,wDataIt1);
385 //ancienne version template processBoundedDataId<DataManipulator>(dataToTransmit,expectedDataId,wDataIt1);
386 //BDIP processBoundedDataId;
387 processBoundedDataId.apply(dataToTransmit,expectedDataId,wDataIt1);
389 // Il ne peut pas y avoir déjà une clé expectedDataId dans storedDatas (utilisation de la notation [] )
390 // Cette opération n'a peut être pas un caractère générique.
391 // A déplacer en paramètre de la méthode précédente ?
392 storedDatas[expectedDataId]=dataToTransmit;
394 std::cout << "-------- Get : Données calculées à t : " << std::endl;
395 typename DataManipulator::InnerType const * const InIt1 = DataManipulator::getPointer(dataToTransmit);
396 size_t N = DataManipulator::size(dataToTransmit);
398 std::copy(InIt1, InIt1 + N,
399 std::ostream_iterator< InnerType > (std::cout," "));
400 std::cout << std::endl;
401 std::cout << "-------- Get : MARK 9 ------------------" << std::endl;
403 typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
404 processEraseDataId.apply(storedDatas,wDataIt1);
409 // Délègue au mode de couplage la gestion d'une demande de donnée non disponible
410 // si le port est deconnecté
411 typename COUPLING_POLICY::template DisconnectProcessor<DataManipulator> processDisconnect(*this);
412 if ( processDisconnect.apply(storedDatas, expectedDataId, wDataIt1) ) continue;
414 // Réception bloquante sur le dataId demandé
415 // Si l'instance de donnée n'est pas trouvee
416 std::cout << "-------- Get : MARK 10 ------------------" << std::endl;
417 //Positionné à faux dans la méthode put
418 waitingForConvenientDataId = true;
419 std::cout << "-------- Get : MARK 11 ------------------" << std::endl;
421 // Ici on attend que la méthode put recoive la donnée
422 std::cout << "-------- Get : waiting datas ------------------" << std::endl;
423 fflush(stdout);fflush(stderr);
424 cond_instance.wait();
426 std::cout << "-------- Get : MARK 12 ------------------" << std::endl;
430 storedDatas_mutex.unlock();
434 // Deverouille l'acces a la table
435 storedDatas_mutex.unlock();
436 std::cout << "-------- Get : MARK 13 ------------------" << std::endl;
438 // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM
439 // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
440 // c'est eraseDataId qui choisi ou non de supprimer la donnée
441 // Du coup interaction potentielle entre le 0 copy et gestion des niveaux
442 return dataToTransmit;
446 template < typename DataManipulator, typename COUPLING_POLICY >
447 template < typename TimeType,typename TagType>
448 typename DataManipulator::Type
449 GenericPort<DataManipulator, COUPLING_POLICY>::get(TimeType ti,
452 TimeType t = COUPLING_POLICY::getEffectiveTime(ti,tf);
457 // Version du next en 0 copy
458 // ( n'effectue pas de recopie de la donnée trouvée dans storedDatas )
459 template < typename DataManipulator, typename COUPLING_POLICY >
460 template < typename TimeType,typename TagType>
461 typename DataManipulator::Type
462 GenericPort<DataManipulator, COUPLING_POLICY>::next(TimeType &t,
465 typedef typename COUPLING_POLICY::DataId DataId;
467 DataType dataToTransmit;
471 storedDatas_mutex.lock();// Gérer les Exceptions ds le corps de la méthode
473 std::cout << "-------- Next : MARK 1 ---lastDataIdSet ("<<lastDataIdSet<<")---------------" << std::endl;
475 typename DataTable::iterator wDataIt1;
476 wDataIt1 = storedDatas.end();
478 //Recherche le prochain dataId à renvoyer
480 wDataIt1 = storedDatas.upper_bound(lastDataId);
481 else if ( !storedDatas.empty() ) {
482 lastDataIdSet = true;
483 wDataIt1 = storedDatas.begin();
486 while ( storedDatas.empty() || wDataIt1 == storedDatas.end() ) {
488 // Délègue au mode de couplage la gestion d'une demande de donnée non disponible
489 // si le port est deconnecté
490 typename COUPLING_POLICY::template DisconnectProcessor<DataManipulator> processDisconnect(*this);
491 if ( processDisconnect.apply(storedDatas, lastDataId, wDataIt1) ) break;
493 std::cout << "-------- Next : MARK 2 ------------------" << std::endl;
494 //Positionné à faux dans la méthode put
495 waitingForAnyDataId = true;
496 std::cout << "-------- Next : MARK 3 ------------------" << std::endl;
497 // Ici on attend que la méthode put recoive la donnée
498 std::cout << "-------- Next : waiting datas ------------------" << std::endl;
499 fflush(stdout);fflush(stderr);
500 cond_instance.wait();
503 std::cout << "-------- Next : MARK 4 ------------------" << std::endl;
504 wDataIt1 = storedDatas.upper_bound(lastDataId);
506 std::cout << "-------- Next : MARK 5 ------------------" << std::endl;
507 lastDataIdSet = true;
508 wDataIt1 = storedDatas.begin();
512 std::cout << "-------- Next : MARK 6 ------------------" << std::endl;
514 t = getTime( (*wDataIt1).first );
515 tag = getTag ( (*wDataIt1).first );
516 dataToTransmit = (*wDataIt1).second;
518 std::cout << "-------- Next : MARK 7 ------------------" << std::endl;
519 lastDataId = (*wDataIt1).first;
521 typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
522 processEraseDataId.apply(storedDatas, wDataIt1);
524 std::cout << "-------- Next : MARK 8 ------------------" << std::endl;
526 storedDatas_mutex.unlock();
529 storedDatas_mutex.unlock();
531 std::cout << "-------- Next : MARK 9 ------------------" << std::endl;
533 // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM
534 // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
535 // c'est eraseDataId qui choisi ou non de supprimer la donnée
536 // Du coup interaction potentielle entre le 0 copy et gestion des niveaux
537 return dataToTransmit;