Salome HOME
Copyright update 2021
[modules/yacs.git] / src / engine / ComposedNode.cxx
1 // Copyright (C) 2006-2021  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "ComposedNode.hxx"
21 #include "LinkInfo.hxx"
22 #include "Container.hxx"
23 #include "InputPort.hxx"
24 #include "OutputPort.hxx"
25 #include "ServiceNode.hxx"
26 #include "InlineNode.hxx"
27 #include "DataFlowPort.hxx"
28 #include "DataStreamPort.hxx"
29 #include "ElementaryNode.hxx"
30 #include "ComponentInstance.hxx"
31
32 #include <iostream>
33 #include <set>
34 #include <string>
35 #include <sstream>
36 #include <algorithm>
37
38 //#define _DEVDEBUG_
39 #include "YacsTrace.hxx"
40
41 using namespace YACS::ENGINE;
42 using namespace std;
43
44 /*! \class YACS::ENGINE::ComposedNode
45  *  \brief Base class for all composed nodes.
46  *
47  * This is an abstract class that must be specialized.
48  *
49  *  \ingroup Nodes
50  */
51
52 const char ComposedNode::SEP_CHAR_BTW_LEVEL[]=".";
53
54 ComposedNode::ComposedNode(const std::string& name):Node(name)
55 {
56 }
57
58 ComposedNode::ComposedNode(const ComposedNode& other, ComposedNode *father):Node(other,father)
59 {
60 }
61
62 ComposedNode::~ComposedNode()
63 {
64 }
65
66 void ComposedNode::performDuplicationOfPlacement(const Node& other)
67 {
68   const ComposedNode &otherC=*(dynamic_cast<const ComposedNode *>(&other));
69   DeploymentTree treeToDup=otherC.getDeploymentTree();
70   list< ElementaryNode * > clones=otherC.getRecursiveConstituents();
71   vector<Container *> conts=treeToDup.getAllContainers();
72   //iterate on all containers
73   for(vector<Container *>::iterator iterCt=conts.begin();iterCt!=conts.end();iterCt++)
74     {
75       vector<ComponentInstance *> comps=treeToDup.getComponentsLinkedToContainer(*iterCt);
76       Container *contCloned=0;
77       if((*iterCt))
78         contCloned=(*iterCt)->clone();
79
80       //iterate on all component instances linked to the container
81       for(vector<ComponentInstance *>::iterator iterCp=comps.begin();iterCp!=comps.end();iterCp++)
82         {
83           vector<Task *> tasks=treeToDup.getTasksLinkedToComponent(*iterCp);
84           ComponentInstance *curCloned=(*iterCp)->clone();
85           curCloned->setContainer(contCloned);
86           for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
87             {
88               //No risk for static cast : appendTask called by ComposedNode.
89               list< ElementaryNode * >::iterator res=find(clones.begin(),clones.end(),(ElementaryNode *)(*iterT));
90               //No risk here to because called only on cloning process...
91               ServiceNode *nodeC=(ServiceNode *)getChildByName(otherC.getChildName(*res));
92               nodeC->setComponent(curCloned);
93             }
94           curCloned->decrRef();
95         }
96
97       // iterate on all tasks linked to the container
98       vector<Task *> tasks=treeToDup.getTasksLinkedToContainer(*iterCt);
99       for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
100         {
101           std::list< ElementaryNode * >::iterator res=find(clones.begin(),clones.end(),(ElementaryNode *)(*iterT));
102           InlineFuncNode *nodeC=(InlineFuncNode *)getChildByName(otherC.getChildName(*res));
103           nodeC->setContainer(contCloned);
104         }
105
106       // ended with current container
107       if(contCloned)
108         contCloned->decrRef();
109     }
110 }
111
112 void ComposedNode::performShallowDuplicationOfPlacement(const Node& other)
113 {
114   const ComposedNode &otherC=*(dynamic_cast<const ComposedNode *>(&other));
115   DeploymentTree treeToDup=otherC.getDeploymentTree();
116   list< ElementaryNode * > clones=otherC.getRecursiveConstituents();
117   vector<Container *> conts=treeToDup.getAllContainers();
118   //iterate on all containers
119   for(vector<Container *>::iterator iterCt=conts.begin();iterCt!=conts.end();iterCt++)
120     {
121       vector<ComponentInstance *> comps=treeToDup.getComponentsLinkedToContainer(*iterCt);
122       Container *contCloned((*iterCt));
123
124       //iterate on all component instances linked to the container
125       for(vector<ComponentInstance *>::iterator iterCp=comps.begin();iterCp!=comps.end();iterCp++)
126         {
127           vector<Task *> tasks=treeToDup.getTasksLinkedToComponent(*iterCp);
128           ComponentInstance *curCloned((*iterCp));
129           curCloned->setContainer(contCloned);
130           for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
131             {
132               //No risk for static cast : appendTask called by ComposedNode.
133               list< ElementaryNode * >::iterator res=find(clones.begin(),clones.end(),(ElementaryNode *)(*iterT));
134               //No risk here to because called only on cloning process...
135               ServiceNode *nodeC=(ServiceNode *)getChildByName(otherC.getChildName(*res));
136               nodeC->setComponent(curCloned);
137             }
138         }
139
140       // iterate on all tasks linked to the container
141       vector<Task *> tasks=treeToDup.getTasksLinkedToContainer(*iterCt);
142       for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
143         {
144           std::list< ElementaryNode * >::iterator res=find(clones.begin(),clones.end(),(ElementaryNode *)(*iterT));
145           InlineFuncNode *nodeC=(InlineFuncNode *)getChildByName(otherC.getChildName(*res));
146           nodeC->setContainer(contCloned);
147         }
148     }
149 }
150
151 bool ComposedNode::isFinished()
152 {
153   if(_state==YACS::DONE)return true;
154   if(_state==YACS::ERROR)return true;
155   if(_state==YACS::FAILED)return true;
156   if(_state==YACS::DISABLED)return true;
157   return false;
158 }
159
160 void ComposedNode::init(bool start)
161 {
162   Node::init(start);
163 }
164
165 std::string ComposedNode::getName() const
166 {
167   return Node::getName();
168 }
169
170 std::string ComposedNode::getTaskName(Task *task) const
171 {
172   return getChildName(dynamic_cast<ElementaryNode *>(task));
173 }
174
175 //! Essentially for test. Use checkDeploymentTree instead to be sure that returned DeploymentTree is consistent.
176 DeploymentTree ComposedNode::getDeploymentTree() const
177 {
178   DeploymentTree ret;
179   list< ElementaryNode * > tasks=getRecursiveConstituents();
180   for(list< ElementaryNode * >::iterator iter=tasks.begin();iter!=tasks.end();iter++)
181     ret.appendTask(*iter,(*iter)->getDynClonerIfExists(this));
182   return ret;
183 }
184
185 //! Perform check of deployment consistency of the current graph.
186 /*!
187  * \param deep if \b true a deep check is perfomed. Typically has to be called by  an executor before any attempt to launch an execution.
188  */
189 DeploymentTree ComposedNode::checkDeploymentTree(bool deep) const
190 {
191   DeploymentTree ret;
192   list< ElementaryNode * > tasks=getRecursiveConstituents();
193   for(list< ElementaryNode * >::iterator iter=tasks.begin();iter!=tasks.end();iter++)
194     {
195       switch(ret.appendTask(*iter,(*iter)->getDynClonerIfExists(this)))
196         {
197         case DeploymentTree::DUP_TASK_NOT_COMPATIBLE_WITH_EXISTING_TREE:
198           {
199             string what("ComposedNode::checkDeploymentTree : ServiceNode with name \""); what+=(*iter)->getName();
200             what+="\" coexists in a component with an another Task which context is incompatible with it.";
201             throw Exception(what);
202           }
203         case DeploymentTree::DEPLOYABLE_BUT_NOT_SPECIFIED :
204           {
205             if(deep)
206               {
207                 string what("ComposedNode::checkDeploymentTree : ServiceNode with name \""); what+=(*iter)->getName();
208                 what+="\" is deployable but no component is specified on it.";
209                 throw Exception(what);
210               }
211           }
212         }
213     }
214   return ret;
215 }
216
217 std::vector<Task *> ComposedNode::getNextTasks(bool& isMore)
218 {
219   vector<Task *> ret;
220   isMore=false;
221   getReadyTasks(ret);
222   isMore=!ret.empty();
223   return ret;
224 }
225
226 //! Notify the node a task has emitted an event
227 /*!
228  * TO COMMENT MORE
229  * \note Runtime called method. Overloads the Scheduler::notifyFrom abstract method.
230  *       Typically Called in Executor (in a parallel thread or not) by the Task 'task'
231  *       to inform the scheduler that an event coded 'event' (in Executor static const var) happened.
232  *       Contrary to updateStateFrom several levels may exist between 'sender' and 'this'.
233  *
234  * \param sender : task emitting event
235  * \param event  : event emitted
236  *
237  * Called by Executor::functionForTaskExecution on YACS::FINISH event
238  *
239  * Called by Executor::launchTask on YACS::START event
240  *
241  * Calls ComposedNode::updateStateFrom to update state from task to root node
242  */
243 void ComposedNode::notifyFrom(const Task *sender, //* I : task emitting event
244                               YACS::Event event,  //* I : event emitted
245                               const Executor *execInst
246                               )
247 {
248   DEBTRACE("ComposedNode::notifyFrom " << event);
249   ElementaryNode *taskTyped=dynamic_cast<ElementaryNode *>((Task *)sender);
250   YACS::Event curEvent=event;
251   Node *lminus1LevelNode=taskTyped;
252   ComposedNode *curLevelNode=taskTyped->_father;
253   if(!curLevelNode)//Specific case of loop when 0 turn is specified without any enclosing bloc.
254     return ;
255   curEvent=curLevelNode->updateStateFrom(lminus1LevelNode,curEvent,execInst);
256   while(curEvent!=YACS::NOEVENT && curLevelNode!=this)
257     {
258       lminus1LevelNode=curLevelNode;
259       curLevelNode=curLevelNode->_father;
260       curEvent=curLevelNode->updateStateFrom(lminus1LevelNode,curEvent,execInst);
261     }
262 }
263
264 //! Add a dataflow link between two data ports.
265 /*!
266  *  Precondition : 'start' AND 'end' are in/outputPort contained in a node in descendance of 'this'.
267  *  \exception Exception : if incompatibility between input and output (type), or 'start'/'end' 
268  *                         is/are NOT in/outputPort contained in a node in descendance 
269  *                         of 'this', or a multiple link to an input not supporting it.
270  *  \return    true if a new link has been created, false otherwise.
271  */
272
273 bool ComposedNode::edAddLink(OutPort *start, InPort *end)
274 {
275   DEBTRACE("ComposedNode::edAddLink");
276   set<OutPort *> represented;
277
278   start->getAllRepresented(represented);
279   if(represented.size()!=1)
280     {
281       bool ret=false;
282       for(set<OutPort *>::iterator iter=represented.begin();iter!=represented.end();iter++)
283         ret|=edAddLink(*iter,end);
284       return ret;
285     }
286   if(start->isAlreadyLinkedWith(end))
287     return false;
288   ComposedNode* lwstCmnAnctr=getLowestCommonAncestor(start->getNode(),end->getNode());
289   list<ComposedNode *> allAscendanceOfNodeStart=start->getNode()->getAllAscendanceOf(lwstCmnAnctr);
290   list<ComposedNode *> allAscendanceOfNodeEnd=end->getNode()->getAllAscendanceOf(lwstCmnAnctr);
291   checkInMyDescendance(lwstCmnAnctr);
292   lwstCmnAnctr->checkLinkPossibility(start,allAscendanceOfNodeStart,end,allAscendanceOfNodeEnd);
293   ComposedNode *iterS;
294   if(dynamic_cast<ComposedNode *>(start->getNode()))
295     iterS=(ComposedNode *)start->getNode();
296   else
297     iterS=start->getNode()->_father;
298   pair<OutPort *, OutPort *> pO(start,start);
299   while(iterS!=lwstCmnAnctr)
300     {
301       iterS->buildDelegateOf(pO, end, allAscendanceOfNodeEnd);
302       iterS=iterS->_father;
303     }
304   if(dynamic_cast<ComposedNode *>(end->getNode()))
305     iterS=(ComposedNode *)end->getNode();
306   else
307     iterS=end->getNode()->_father;
308
309   InPort *currentPortI=end;
310   bool isLoopProofLink(true),isFirstTurn(true);
311   while(iterS!=lwstCmnAnctr)
312     {
313       if(!isFirstTurn && iterS->isLoop())// isFirstTurn is a way to filter special inputs like nbBranches, splitPort... These special inputs are loopProof -> they must not be realeased by ForEachLoop::exUpdateState
314         isLoopProofLink=false;
315       iterS->buildDelegateOf(currentPortI, start, allAscendanceOfNodeStart);
316       iterS=iterS->_father;
317       isFirstTurn=false;
318     }
319   bool ret=(pO.first)->addInPort(currentPortI);
320   end->edNotifyReferencedBy(pO.second,isLoopProofLink);
321   return ret;
322 }
323
324 //! Connect an OutPort to an InPort and add the necessary control link
325 /*!
326  * Connect the ports with a data link (edAddLink) and add
327  * a control flow link between the children of the lowest common ancestor node.
328  *
329  * \param start : the OutPort to connect
330  * \param end : the InPort to connect
331  * \return  true if a new link has been created, false otherwise. 
332  */
333 bool ComposedNode::edAddDFLink(OutPort *start, InPort *end)
334 {
335   Node* n1=start->getNode();
336   Node* n2=end->getNode();
337   DEBTRACE( n1->getName() << ":" << n2->getName())
338   ComposedNode* father=getLowestCommonAncestor(n1,n2);
339   DEBTRACE( "ComposedNode::edAddDFLink: this="<<this->getName() 
340             << " father=" << father->getName() )
341   DEBTRACE( "ComposedNode::edAddDFLink: OutPort=" << start->getName()
342             << " InPort=" << end->getName() )
343   if (father != this)
344     {
345       bool ret = father->edAddDFLink(start,end); // special treatement for loop
346       return ret;
347     }
348   if(n2 == father)
349     throw Exception("Back link authorized only in special context (loop for example)");
350
351   bool ret= edAddLink(start,end);
352   if(n1 != father)
353     {
354       //add a control link only if nodes are not in the same descendance
355       //if n1 == father (n2 is after n1) : the control link is not needed 
356       //if n2 == father (n1 is after n2) : it's a back link authorized only in loop context
357       while(n1->getFather() != father)
358         n1=n1->getFather();
359       while(n2->getFather() != father)
360         n2=n2->getFather();
361       try
362         {
363           edAddCFLink(n1,n2);
364         }
365       catch (Exception& ex)
366         {
367           // --- remove DF link already created in case of cycle dtection
368           DEBTRACE("Cycle detected, remove CF link");
369           if(start->isAlreadyLinkedWith(end))
370             edRemoveLink(start, end);
371           throw ex;          
372         }
373     }
374   return ret;
375 }
376
377 //! Add a controlflow link between two control ports.
378 /*!
379  * \note Precondition : 'start' AND 'end' are in/outGate contained in a node 
380  *       in DIRECT descendance of 'this'.
381  * \exception Exception : If a cycle has been detected, or incompatibility 
382  *             between input and output, or 'start'/'end' is/are NOT in/outputPort contained 
383  *             in a node in descendance of 'this', or a mutilple link to an input not 
384  *             supporting it.
385  * \return  true if a new link has been created, false otherwise. 
386  */
387 bool ComposedNode::edAddLink(OutGate *start, InGate *end)
388 {
389   Node* n1=start->getNode();
390   Node* n2=end->getNode();
391   if(n1==n2)
392     throw Exception("ComposedNode::edAddLink: can not add a control link to a node with itself",1);
393   ComposedNode* father=checkHavingCommonFather(start->getNode(),end->getNode());
394   if(father==0)
395     throw Exception("ComposedNode::edAddLink: Trying to add CF link on orphan nodes.");
396   if(father!=this)
397     {
398       checkInMyDescendance(father);
399       return father->edAddLink(start,end);
400     }
401   bool ret=start->edAddInGate(end);
402   if(ret)
403     try
404       {
405         checkNoCyclePassingThrough(end->getNode());
406       }
407     catch (Exception& ex)
408       {
409         // --- remove  created CF link in case of cycle detection
410         DEBTRACE("Cycle detected, remove CF link");
411         edRemoveCFLink(start->getNode(), end->getNode());
412         throw ex;
413       }
414   return ret;
415 }
416
417 //! Add a controlflow link between two nodes.
418 /*!
419  * Add a controlflow link between two nodes by calling edAddLink on their control ports
420  */
421 bool ComposedNode::edAddCFLink(Node *nodeS, Node *nodeE)
422 {
423   return edAddLink(nodeS->getOutGate(),nodeE->getInGate());
424 }
425
426 //! Remove a controlflow link.
427 void ComposedNode::edRemoveCFLink(Node *nodeS, Node *nodeE)
428 {
429   edRemoveLink(nodeS->getOutGate(),nodeE->getInGate());
430 }
431
432 //! Remove a dataflow link.
433 /*!
434  * Precondition : 'start' AND 'end' are in/outputPort contained in a node in descendance of 'this'.
435  *
436  * \exception Exception : If the specified link does not exist. The content of Exception 
437  *                        is different in accordance with the link from 'start' to 'end' 
438  *                        implies DF/DS gateway.
439  */
440
441 void ComposedNode::edRemoveLink(OutPort *start, InPort *end)
442 {
443   if(!start->isAlreadyLinkedWith(end))
444     throw Exception("ComposedNode::edRemoveLink : unexisting link");
445   ComposedNode* lwstCmnAnctr=getLowestCommonAncestor(start->getNode(),end->getNode());
446   checkInMyDescendance(lwstCmnAnctr);
447   list<ComposedNode *> allAscendanceOfNodeStart=start->getNode()->getAllAscendanceOf(lwstCmnAnctr);
448   list<ComposedNode *> allAscendanceOfNodeEnd=end->getNode()->getAllAscendanceOf(lwstCmnAnctr);
449
450   // --- Part of test if the link from 'start' to 'end' really exist particulary all eventually intermediate ports created
451
452   ComposedNode *iterS=start->getNode()->_father;
453   pair<OutPort *,OutPort *> currentPortO(start,start);
454   vector<pair< ComposedNode * , pair < OutPort* , OutPort *> > > needsToDestroyO;
455
456   Node *nodeOTemp=start->getNode();
457   if(*nodeOTemp<*lwstCmnAnctr)
458     {
459       iterS=nodeOTemp->_father;
460       while(iterS!=lwstCmnAnctr)
461         {
462           if (!iterS)
463             {
464               stringstream what;
465               what << "ComposedNode::edRemoveLink: "
466                    << start->getNode()->getName() << "." <<start->getName() << "->"
467                    << end->getNode()->getName() << "." << end->getName();
468               throw Exception(what.str());
469             }
470           OutPort *tmp=currentPortO.first;
471           iterS->getDelegateOf(currentPortO, end, allAscendanceOfNodeEnd);
472           needsToDestroyO.push_back(pair< ComposedNode * , pair < OutPort* , OutPort *> >(iterS,pair<OutPort* , OutPort *> (tmp,currentPortO.first)));
473           iterS=iterS->_father;
474         }
475     }
476   Node *nodeTemp=end->getNode();
477   InPort * currentPortI=end;
478   if(*nodeTemp<*lwstCmnAnctr)
479     {
480       iterS=nodeTemp->_father;    
481       while(iterS!=lwstCmnAnctr)
482         {
483           if (!iterS)
484             {
485               stringstream what;
486               what << "ComposedNode::edRemoveLink: "
487                    << start->getNode()->getName() << "." <<start->getName() << "->"
488                    << end->getNode()->getName() << "." << end->getName();
489               throw Exception(what.str());
490             }
491           iterS->getDelegateOf(currentPortI, start, allAscendanceOfNodeStart);
492           iterS=iterS->_father;
493         }
494     }
495   // --- End of test for evt intermediate ports created
496   
497   (currentPortO.first)->removeInPort(currentPortI,false);
498   set<OutPort *> repr;
499   (currentPortO.second)->getAllRepresented(repr);
500   if(repr.size()==1)
501     end->edNotifyDereferencedBy(currentPortO.second);
502
503   // --- Performing deletion of intermediate ports
504   
505   iterS=start->getNode()->_father;
506   vector<pair< ComposedNode * , pair < OutPort* , OutPort *> > >::reverse_iterator iter;
507   for(iter=needsToDestroyO.rbegin();iter!=needsToDestroyO.rend();iter++)
508     (*iter).first->releaseDelegateOf(((*iter).second).first, ((*iter).second).second, end,allAscendanceOfNodeEnd);
509   nodeTemp=end->getNode();
510   if(*nodeTemp<*lwstCmnAnctr)
511     {
512       iterS=end->getNode()->_father;
513       currentPortI=end;
514       while(iterS!=lwstCmnAnctr)
515         {
516           iterS->releaseDelegateOf(currentPortI, start, allAscendanceOfNodeStart);
517           iterS=iterS->_father;
518         }
519     }
520 }
521
522 //! Remove a controlflow link.
523 void ComposedNode::edRemoveLink(OutGate *start, InGate *end)
524 {
525   ComposedNode* father=checkHavingCommonFather(start->getNode(),end->getNode());
526   if(father!=this)
527     throw Exception("edRemoveLink : nodes not in direct descendance of this");
528   start->edRemoveInGate(end);
529 }
530
531 bool ComposedNode::edAddChild(Node *DISOWNnode)
532 {
533   return false; // --- reimplemented in derived classes
534 }
535
536 //! Remove a child node.
537 void ComposedNode::edRemoveChild(Node *node)
538 {
539   if(!node)
540     return;
541   if (node->_father!=this)
542     {
543       string what("node "); what+= node->getName() ; what+=" is not a child of node "; what += getName();
544       throw Exception(what);
545     }
546   node->edDisconnectAllLinksWithMe();
547   node->_father = 0;
548   //set _modified flag so edUpdateState() can refresh state
549   modified();
550 }
551
552 //! Splits name globalName in 2 parts using separator.
553 /*!
554  * \note   'priority' specifies if during search process of 'separator' the max part is 
555  *         for 'firstPart' (priority=true) or 'lastPart' (priority=false).
556  *
557  * \throw Exception : 'lastPart' or 'firstPart' is empty.
558  * \return  true if split process succeeds false otherwise (typically when character 
559  *          separator was not found).
560  */
561 bool ComposedNode::splitNamesBySep(const std::string& globalName, const char separator[],
562                                    std::string& firstPart, std::string& lastPart, bool priority)
563 {
564   const string delims(separator);
565   string portName, nodeName;
566   string::size_type idx;
567   if(priority)
568     idx = globalName.find_last_of(delims);
569   else
570     idx = globalName.find_first_of(delims);
571   if (idx == string::npos)
572     {
573       firstPart=globalName;
574       lastPart="";
575       return false;
576     }
577   firstPart = globalName.substr(0,idx);
578   lastPart = globalName.substr(idx+1);
579   if ((firstPart.empty()) || (lastPart.empty()))
580     {
581       string what("the name "); what+= globalName ; what+=" is not a valid port name";
582       throw Exception(what);
583     }
584   return true;
585 }
586
587 std::vector< std::pair<OutPort *, InPort *> > ComposedNode::getSetOfInternalLinks() const
588 {
589   vector< pair<OutPort *, InPort *> > ret;
590   list<OutPort *> temp=getSetOfOutPort();
591   for(list<OutPort *>::const_iterator iter2=temp.begin();iter2!=temp.end();iter2++)
592     {
593       set<InPort *> temp2=(*iter2)->edSetInPort();
594       for(set<InPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
595         if(isInMyDescendance((*iter3)->getNode()))
596           ret.push_back(pair<OutPort *, InPort *>((*iter2),(*iter3)));
597     }
598   return ret;
599 }
600
601 std::vector< std::pair<OutPort *, InPort *> > ComposedNode::getSetOfLinksLeavingCurrentScope() const
602 {
603   vector< pair<OutPort *, InPort *> > ret;
604   std::set<OutPort *> ports=getAllOutPortsLeavingCurrentScope();
605   for(set<OutPort *>::iterator iter2=ports.begin();iter2!=ports.end();iter2++)
606     {
607       set<InPort *> temp2=(*iter2)->edSetInPort();
608       for(set<InPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
609         if(!isInMyDescendance((*iter3)->getNode()))
610           ret.push_back(pair<OutPort *, InPort *>(*iter2,*iter3));
611     }
612   return ret;
613 }
614
615 void ComposedNode::checkConsistency(LinkInfo& info) const
616 {
617   info.clearAll();
618   info.setPointOfView((ComposedNode *)this);
619   performCFComputations(info);
620   list<InputPort *> setOfInToTest=getSetOfInputPort();
621   for(list<InputPort *>::iterator iter1=setOfInToTest.begin();iter1!=setOfInToTest.end();iter1++)
622     {
623       vector<OutPort *> candidateForAdvCheck;
624       set<OutPort *> outPorts=(*iter1)->edSetOutPort();
625       //Filtering among outPorts, which of them, are candidates to fill *iter1 at the current scope.
626       for(set<OutPort *>::iterator iter2=outPorts.begin();iter2!=outPorts.end();iter2++)
627         {
628           (*iter2)->checkConsistency(info);
629           ComposedNode *manager=getLowestCommonAncestor((*iter2)->getNode(),(*iter1)->getNode());
630           if(isInMyDescendance(manager))
631             candidateForAdvCheck.push_back(*iter2);
632         }
633       if(!candidateForAdvCheck.empty())
634         //End of filtering. Now regarding CF constraints for the current InPutPort.
635         try
636           {
637             checkLinksCoherenceRegardingControl(candidateForAdvCheck,*iter1,info);
638           }
639         catch(YACS::Exception& ex)
640           {
641             std::string what=ex.what();
642             what += "\nfor input port: ";
643             what += (*iter1)->getNode()->getName();
644             what += ".";
645             what += (*iter1)->getName();
646
647             destructCFComputations(info);
648             throw YACS::Exception(what);
649           }
650       else
651         //No backlinks
652         if(!(*iter1)->canBeNull() && !(*iter1)->edIsManuallyInitialized())
653           info.pushErrLink(0,*iter1,E_NEVER_SET_INPUTPORT);
654     }
655   destructCFComputations(info);
656 }
657
658 /*!
659  * This method check that G1 <- G2 <- G3 <- G1 does not happened.
660  * Typically called by methods that set a hierarchy (Bloc::edAddChild, Loop::edSetNode, ...).
661  */
662 void ComposedNode::checkNoCrossHierachyWith(Node *node) const
663 {
664   ComposedNode *nodeC=dynamic_cast<ComposedNode *>(node);
665   if(!nodeC)
666     return ;
667   list<ComposedNode *> ascendants=getAllAscendanceOf();
668   if(find(ascendants.begin(),ascendants.end(),nodeC)!=ascendants.end())
669     {
670       const char what[]="ComposedNode::checkNoCrossHierachyWith : ComposedNode with name \"";
671       string stream(what); stream+=node->getName(); stream+="\" is already in hierarchy ascendance of node with name \"";
672       stream+=_name; stream+="\" ; So it can't be now in its descendance !";
673       throw Exception(stream);
674     }
675 }
676
677 //! perform \b recursively all CF computations.
678 void ComposedNode::performCFComputations(LinkInfo& info) const
679 {
680   list<Node *> nodes=edGetDirectDescendants();
681   for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
682     if(dynamic_cast<ComposedNode *>(*iter))
683       ((ComposedNode *)(*iter))->performCFComputations(info);
684 }
685
686 //! destroy \b recursively all results of initial computations.
687 void ComposedNode::destructCFComputations(LinkInfo& info) const
688 {
689   list<Node *> nodes=edGetDirectDescendants();
690   for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
691     if(dynamic_cast<ComposedNode *>(*iter))
692       ((ComposedNode *)(*iter))->destructCFComputations(info);
693 }
694
695 /*!
696  * Returns the lowest Node (Elementary or Composed) (is sense of hierachy level ( operator< ) ) containing all 'ports'.
697  * Typically use in consistency computation.
698  * Precondition : 'ports' \b must contain at least one element. All elements of 'ports' should be in descendance of 'this'.
699  */
700 Node *ComposedNode::getLowestNodeDealingAll(const std::list<OutPort *>& ports) const
701 {
702   list< OutPort *>::const_iterator iter=ports.begin();
703   Node *ret=(*iter)->getNode();
704   iter++;
705   for(;iter!=ports.end();iter++)
706     {
707       Node *tmp=(*iter)->getNode();
708       if(*tmp>*ret)
709         ret=tmp;
710     }
711   return ret;
712 }
713
714 /*!
715  * call it only for 'starts' to 'end' links \b DEALED by 'this'.
716  */
717 void ComposedNode::checkLinksCoherenceRegardingControl(const std::vector<OutPort *>& starts, InputPort *end, LinkInfo& info) const
718 {
719   map < ComposedNode *, list<OutPort *>, SortHierarc > outputs;//forward link classical
720   vector<OutPort *> outputsCross;//forward link cross
721   map < ComposedNode *, list<OutPort *>, SortHierarc > outputsBw;//backward
722   vector<OutPort *>::const_iterator iter1;
723   //vector<DataPort *> history=((*iter1).second)[0]->calculateHistoryOfLinkWith(end);
724   //DataPort *cross=DataPort::isCrossingType(history);
725   for(iter1=starts.begin();iter1!=starts.end();iter1++)
726     {
727       ComposedNode *manager=getLowestCommonAncestor((*iter1)->getNode(),end->getNode());
728       manager->checkControlDependancy((*iter1), end, false, outputs, outputsCross, outputsBw, info);
729     }
730   //Ok now let's regarding outputs all combinations : (outputs.size())*(outputs.size()-1)/2
731   unsigned char isAlreadyFed=FREE_ST;
732   //Dealing excusively with DS. Level is useless here because simultaneity is required for DS.
733   if(outputsCross.size()>0)
734     {
735       isAlreadyFed=FED_DS_ST;
736       if(outputsCross.size()>1)
737         for(vector< OutPort *>::const_iterator iter1=outputsCross.begin();iter1!=(outputsCross.end()-2);iter1++)
738           info.pushErrLink(*iter1,end,E_COLLAPSE_DS);
739     }
740   map < ComposedNode *, list<OutPort *>, SortHierarc >::iterator iter3=outputs.begin();
741   for(;iter3!=outputs.end();iter3++)
742     ((*iter3).first)->checkCFLinks((*iter3).second,end,isAlreadyFed,true,info);
743   if(isAlreadyFed==FREE_ST)
744     if(!end->edIsManuallyInitialized())
745       info.pushErrLink(0,end,E_ONLY_BACKWARD_DEFINED);
746   isAlreadyFed=FREE_ST;
747   //
748   map < ComposedNode *, list<OutPort *>, SortHierarc >::reverse_iterator iter5=outputsBw.rbegin();
749   for(;iter5!=outputsBw.rend();iter5++)
750     ((*iter5).first)->checkCFLinks((*iter5).second,end,isAlreadyFed,false,info);
751 }
752
753 /*!
754  * Internal method during CF links. This methode is in charge to statuate on links consistency in the case 
755  * that no control flow defined by user is set.
756  */
757 void ComposedNode::solveObviousOrDelegateCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
758 {
759   static const char what[]="ComposedNode::solveObviousOrDelegateCFLinks : Internal error occured - uncorrect hierarchy detected !";
760   if(starts.size()==1)
761     {
762       if(alreadyFed==FREE_ST)
763         {
764           if(!direction)
765             info.pushInfoLink(*(starts.begin()),end,I_BACK);
766           alreadyFed=FED_ST;
767         }
768       else if(alreadyFed==FED_ST)
769         info.pushInfoLink(*(starts.begin()),end,direction ?  I_USELESS : I_BACK_USELESS);
770       else
771         info.pushErrLink(*(starts.begin()),end,E_COLLAPSE_DFDS);
772     }
773   else
774     {
775       Node *levelOfDecision=getLowestNodeDealingAll(starts);
776       if(levelOfDecision==this)
777         throw Exception(what);
778       if(dynamic_cast<ElementaryNode *>(levelOfDecision))
779         {
780           WarnReason reason;
781           if(alreadyFed==FREE_ST || alreadyFed==FED_ST)
782             {
783               if(alreadyFed==FREE_ST)
784                 {
785                   reason=direction ? W_COLLAPSE_EL : W_BACK_COLLAPSE_EL;
786                   alreadyFed=FED_ST;
787                 }
788               else
789                 reason=direction ? W_COLLAPSE_EL_AND_USELESS : W_BACK_COLLAPSE_EL_AND_USELESS;
790               for(list< OutPort *>::const_iterator iter=starts.begin();iter!=starts.end();iter++)
791                 info.pushWarnLink(*iter,end,reason);
792             }
793         }
794       else
795         ((ComposedNode *)levelOfDecision)->checkCFLinks(starts,end,alreadyFed,direction,info);
796     }
797 }
798
799 //! check control flow links
800 /*!
801  * \param starts If different of 0, must aggregate at leat \b 1 element.
802  * \param end :
803  * \param alreadyFed in/out parameter. Indicates if 'end' ports is already and surely set or fed by an another port.
804  * \param direction If true : forward direction else backward direction.
805  * \param info : informations collectedduring the check
806  */
807 void ComposedNode::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
808 {
809   static const char what[]="ComposedNode::checkCFLinks : Internal error occured - uncorrect hierarchy detected !";
810   Node *nodeEnd=isInMyDescendance(end->getNode());
811   if(!nodeEnd)
812     return solveObviousOrDelegateCFLinks(starts,end,alreadyFed,direction,info);
813   //This case is typically dedicated when direct son is ElementaryNode and self link is defined on this.
814   if(!dynamic_cast<ElementaryNode *>(nodeEnd))
815     throw Exception(what);
816
817   list< OutPort *>::const_iterator iter=starts.begin();
818   Node *nodeStart=(*iter)->getNode();
819   iter++;
820   if(nodeEnd!=nodeStart)
821     throw Exception(what);
822
823   for(;iter!=starts.end();iter++)
824     if((*iter)->getNode()!=nodeStart)
825       throw Exception(what);
826   //Ok at this step we are sure that we have back links on the same elementary node.
827   if(starts.size()>1)
828     for(iter=starts.begin();iter!=starts.end();iter++)
829       info.pushWarnLink(*iter,end,W_BACK_COLLAPSE_EL);
830   else//here no need to look at 'alreadyFed' var because it is waranteed to be equal to FREE_ST by construction.
831     info.pushInfoLink(*(starts.begin()),end,I_BACK);
832   alreadyFed=FED_ST;
833 }
834
835 std::vector< std::pair<InPort *, OutPort *> > ComposedNode::getSetOfLinksComingInCurrentScope() const
836 {
837   vector< pair<InPort *, OutPort *> > ret;
838   set<InPort *> ports=getAllInPortsComingFromOutsideOfCurrentScope();
839   for(set<InPort *>::iterator iter2=ports.begin();iter2!=ports.end();iter2++)
840     {
841       set<OutPort *> temp2=(*iter2)->edSetOutPort();
842       for(set<OutPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
843         {
844           if(isInMyDescendance((*iter3)->getNode()))continue;
845           std::set<OutPort *> trueOutPorts;
846           (*iter3)->getAllRepresented(trueOutPorts);
847           for(std::set<OutPort *>::iterator iter4=trueOutPorts.begin();iter4!=trueOutPorts.end();++iter4)
848             ret.push_back(pair<InPort *, OutPort *>(*iter2,*iter4));
849         }
850     }
851   return ret;
852 }
853
854 //! List all output ports of children nodes that are linked to out of scope input ports
855 /*!
856  * \note List all output ports of nodes sons of 'this' that are linked to input ports 
857  *       of nodes not in descendance of 'this'.
858  *       This method contrary to getAllInPortsComingFromOutsideOfCurrentScope is NOT virtual 
859  *       because for the moment all daughter classes have no more hidden YACS::ENGINE::OutPort.
860  */
861 std::set<OutPort *> ComposedNode::getAllOutPortsLeavingCurrentScope() const
862 {
863   set<OutPort *> ret;
864   list<OutPort *> temp=getSetOfOutPort();
865   for(list<OutPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
866     {
867       set<InPort *> temp2=(*iter2)->edSetInPort();
868       for(set<InPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
869         if(!isInMyDescendance((*iter3)->getNode()))
870           {
871             ret.insert(*iter2);
872             break;
873           }
874     }
875   return ret;
876 }
877
878 //! List all input ports that are linked to out of scope ports
879 /*!
880  *
881  * List all input ports of 'this' so that, for each it exists at least 1 link coming 
882  * from outside to it.
883  *
884  */
885 std::set<InPort *> ComposedNode::getAllInPortsComingFromOutsideOfCurrentScope() const
886 {
887   set<InPort *> ret;
888   list<InPort *> temp=getSetOfInPort();
889   for(list<InPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
890     {
891       set<OutPort *> temp2=(*iter2)->edSetOutPort();
892       for(set<OutPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
893         if(*iter3)
894           if(!isInMyDescendance((*iter3)->getNode()))
895             {
896               ret.insert(*iter2);
897               break;
898             }
899     }
900   return ret;
901 }
902
903 void ComposedNode::edDisconnectAllLinksWithMe()
904 {
905   //CF
906   DEBTRACE("-");
907   Node::edDisconnectAllLinksWithMe();
908   //Leaving part
909   DEBTRACE("--");
910   vector< pair<OutPort *, InPort *> > linksToDestroy=getSetOfLinksLeavingCurrentScope();
911   vector< pair<OutPort *, InPort *> >::iterator iter;
912   for(iter=linksToDestroy.begin();iter!=linksToDestroy.end();iter++)
913     {
914       DEBTRACE("---");
915       (*iter).first->removeInPort((*iter).second,true);
916     }
917   //Arriving part
918   vector< pair<InPort *, OutPort *> > linksToDestroy2=getSetOfLinksComingInCurrentScope();
919   vector< pair<InPort *, OutPort *> >::iterator iter2;
920   for(iter2=linksToDestroy2.begin();iter2!=linksToDestroy2.end();iter2++)
921     {
922       DEBTRACE("----");
923       (*iter2).second->removeInPort((*iter2).first,true);
924     }
925 }
926
927 ComposedNode *ComposedNode::getRootNode() const
928 {
929   if(!_father)
930     return (ComposedNode *)this;
931   return Node::getRootNode();
932 }
933
934 //! Check that Node 'node' is already a direct son of this.
935 bool ComposedNode::isNodeAlreadyAggregated(const Node *node) const
936 {
937   list<ComposedNode *> nodeAncestors = node->getAllAscendanceOf();
938   return find(nodeAncestors.begin(),nodeAncestors.end(),(ComposedNode *)this)!=nodeAncestors.end();
939 }
940
941 //! Returns the parent of a node that is the direct child of this node 
942 /*!
943  * \note if 'nodeToTest'=='this' this is returned. Else if 'nodeToTest' is in descendance of
944  *       'this' the direct son is returned. 
945  *       Else 0 is returned. 
946  *
947  * \param nodeToTest : the node to check
948  */
949 Node *ComposedNode::isInMyDescendance(Node *nodeToTest) const
950 {
951   if(nodeToTest==0)
952     return 0;
953   if((ComposedNode *)nodeToTest==this)
954     return (Node *)this;
955   Node *iterBack=nodeToTest;
956   ComposedNode *iter=nodeToTest->_father;
957   while(iter!=0 && iter!=this)
958     {
959       iterBack=iter;
960       iter=iter->_father;
961     }
962   if(iter!=0)
963     return iterBack;
964   else
965     return 0;
966 }
967
968 string ComposedNode::getChildName(const Node* node) const
969 {
970   string nodeName=node->getQualifiedName();    
971   if (!isNodeAlreadyAggregated(node))
972     {
973       if (node->getName() == "thisIsAFakeNode")
974         {
975           string child = node->getName()+".thisIsAFakeNode";
976           return child;
977         }
978       else
979         {
980           string what("node "); what+= node->getName() ; what+=" is not a child of node "; what += getName();
981           throw Exception(what);
982         }
983     }
984   
985   const Node *father = node->_father;
986   while (father != this)
987     {
988       nodeName = father->getQualifiedName() + SEP_CHAR_BTW_LEVEL + nodeName;
989       father = father->_father;
990     }
991   return nodeName;
992 }
993
994 std::string ComposedNode::getMyQualifiedName(const Node *directSon) const
995 {
996   return directSon->getName();
997 }
998
999 Node *ComposedNode::getChildByName(const std::string& name) const
1000 {
1001   string potentiallyDirectSonName, remainsPath;
1002   bool forwardNeeded=ComposedNode::splitNamesBySep(name, SEP_CHAR_BTW_LEVEL,
1003                                                    potentiallyDirectSonName,remainsPath,false);
1004   Node *child=getChildByShortName(potentiallyDirectSonName);
1005   if(!forwardNeeded)
1006     return child;
1007   else
1008     return child->getChildByName(remainsPath);
1009 }
1010
1011 //! Check if a node is in the descendance of this node
1012 /*!
1013  * \note Check that 'nodeToTest' is in descendance of 'this' OR equal to 'this'
1014  * \exception Exception : If 'nodeToTest' is NOT in descendance of 'this' AND not equal to 'this'
1015  * \param nodeToTest : the node to check
1016  */
1017 void ComposedNode::checkInMyDescendance(Node *nodeToTest) const
1018 {
1019   const char whatC[]=" is not the descendance of node ";
1020   if(nodeToTest==0)
1021     {
1022       string what("node "); what+= nodeToTest->getName(); what+=" ";
1023       what+=whatC; what+=_name;
1024       throw Exception(what);
1025     }
1026   if((ComposedNode *)nodeToTest==this)
1027     return;
1028   ComposedNode *iter=nodeToTest->_father;
1029   while(iter!=0 && iter!=this)
1030     iter=iter->_father;
1031   if(iter==0)
1032     {
1033       string what("node "); what+= nodeToTest->getName(); what+=" ";
1034       what+=whatC; what+=_name;
1035       throw Exception(what);
1036     }
1037 }
1038
1039 //! Retrieves the lowest common ancestor of 2 nodes
1040 /*!
1041  * 
1042  * \note Retrieves the lowest common ancestor of 'node1' AND 'node2'. 
1043  *       If  'node1' or 'node2' are both or indiscriminately instances of ComposedNode and that
1044  *       'node1' is in descendance of 'node2' (resp. 'node2' in descendance of 'node1')
1045  *       'node2' is returned (resp. 'node1').
1046  * \exception Exception : if 'node1' and 'node2' do not share the same genealogy.
1047  * \return The lowest common ancestor if it exists.
1048  *
1049  */
1050 ComposedNode *ComposedNode::getLowestCommonAncestor(Node *node1, Node *node2)
1051 {
1052   const char what[]="The two nodes do not share the same genealogy";
1053   if(node1==0 || node2==0)
1054     throw Exception(what);
1055   ComposedNode *temp;
1056   if(dynamic_cast<ComposedNode *>(node1))
1057     temp=(ComposedNode *)node1;//->_father;
1058   else
1059     temp=(ComposedNode *)node1->_father;
1060   set<ComposedNode *> s;
1061   while(temp)
1062     {
1063       s.insert(temp);
1064       temp=temp->_father;
1065     }
1066   //
1067   if(dynamic_cast<ComposedNode *>(node2))
1068     temp=(ComposedNode *)node2;//->_father;
1069   else
1070     temp=(ComposedNode *)node2->_father;
1071   set<ComposedNode *>::iterator iter=s.find(temp);
1072   while(temp && iter==s.end())
1073     {
1074       iter=s.find(temp);
1075       temp=temp->_father;
1076     }
1077   if(iter==s.end())
1078     throw Exception(what);
1079   return *iter;
1080 }
1081
1082 /*!
1083  * Same as getLowestCommonAncestor method except that absolute string representation is considered here instead of instances.
1084  */
1085 std::string ComposedNode::getLowestCommonAncestorStr(const std::string& node1, const std::string& node2)
1086 {
1087   std::string ret;
1088   std::size_t it1_b(0),it1_e(0),it2_b(0),it2_e(0);
1089   while(it1_b!=std::string::npos && it2_b!=std::string::npos)
1090     {
1091       it1_e=node1.find(SEP_CHAR_BTW_LEVEL,it1_b);
1092       it2_e=node2.find(SEP_CHAR_BTW_LEVEL,it2_b);
1093       if(it1_e!=it2_e && it1_e!=std::string::npos && it2_e!=std::string::npos)
1094         break;
1095       std::string elt1(node1.substr(it1_b,it1_e-it1_b)),elt2(node2.substr(it2_b,it2_e-it2_b));
1096       if(elt1!=elt2)
1097         break;
1098       if(!ret.empty())
1099         ret+=SEP_CHAR_BTW_LEVEL;
1100       ret+=elt1;
1101       it1_b=node1.find_first_not_of(SEP_CHAR_BTW_LEVEL,it1_e);
1102       it2_b=node2.find_first_not_of(SEP_CHAR_BTW_LEVEL,it2_e);
1103     }
1104   return ret;
1105 }
1106
1107 /*!
1108  * This method recursively all redundant control links in this.
1109  */
1110 void ComposedNode::removeRecursivelyRedundantCL()
1111 {
1112   std::list<Node *> dd(edGetDirectDescendants());
1113   for(std::list<Node *>::const_iterator it=dd.begin();it!=dd.end();it++)
1114     {
1115       ComposedNode *elt(dynamic_cast<ComposedNode *>(*it));
1116       if(elt)
1117         elt->removeRecursivelyRedundantCL();
1118     }
1119 }
1120
1121 list<ElementaryNode *> ComposedNode::getRecursiveConstituents() const
1122 {
1123   list<ElementaryNode *> ret;
1124   list<Node *> setOfNode=edGetDirectDescendants();
1125   for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1126     {
1127       list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
1128       ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1129     }
1130   return ret;
1131 }
1132
1133 //! Idem getAllRecursiveNodes, but this node is NOT included.
1134 list<Node *> ComposedNode::getAllRecursiveConstituents()
1135 {
1136   list<Node *> ret;
1137   list<Node *> setOfNode=edGetDirectDescendants();
1138   for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1139     {
1140       if ( dynamic_cast<ComposedNode*> (*iter) )
1141         {
1142           list<Node *> myCurrentSet=((ComposedNode*)(*iter))->getAllRecursiveConstituents();
1143           ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1144           ret.push_back(*iter);
1145         }
1146       else
1147         {
1148           list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
1149           ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1150         }
1151     }
1152   return ret;
1153 }
1154
1155 //! Get all children nodes  elementary and composed including this node
1156 list<Node *> ComposedNode::getAllRecursiveNodes()
1157 {
1158   list<Node *> ret;
1159   list<Node *> setOfNode=edGetDirectDescendants();
1160   for(list<Node *>::iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1161     {
1162       if ( dynamic_cast<ElementaryNode*> (*iter) )
1163         {
1164           list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
1165           ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1166         }
1167       else
1168         {
1169           list<Node *> myCurrentSet=((ComposedNode*)(*iter))->getAllRecursiveNodes();
1170           ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1171         }
1172     }
1173   ret.push_back(this);
1174   return ret;
1175 }
1176
1177
1178 //! Get the progress weight for all elementary nodes
1179 /*!
1180  * Only elementary nodes have weight. A simple composed node only sum up weight of all his descendants
1181  * (working is different for loop or switch nodes)
1182  */
1183 list<ProgressWeight> ComposedNode::getProgressWeight() const
1184 {
1185   list<ProgressWeight> ret;
1186   list<Node *> setOfNode=edGetDirectDescendants();
1187   for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1188     {
1189       list<ProgressWeight> myCurrentSet=((ComposedNode*)(*iter))->getProgressWeight();
1190       ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1191     }
1192   return ret;
1193 }
1194
1195 //! Get the input port name 
1196 /*!
1197  * get the input port name used by the current node, recursively built with children names.
1198  */
1199
1200 string ComposedNode::getInPortName(const InPort * inPort) const
1201 {
1202   return getPortName<InPort>(inPort);
1203 }
1204
1205 string ComposedNode::getOutPortName(const OutPort *outPort) const
1206 {
1207   return getPortName<OutPort>(outPort);
1208 }
1209
1210 int ComposedNode::getNumberOfInputPorts() const
1211 {
1212   list<Node *> constituents=edGetDirectDescendants();
1213   int ret=0;
1214   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1215     ret+=(*iter)->getNumberOfInputPorts();
1216   return ret;
1217 }
1218
1219 int ComposedNode::getNumberOfOutputPorts() const
1220 {
1221   list<Node *> constituents=edGetDirectDescendants();
1222   int ret=0;
1223   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1224     ret+=(*iter)->getNumberOfOutputPorts();
1225   return ret;
1226 }
1227
1228 list<InputPort *> ComposedNode::getSetOfInputPort() const
1229 {
1230   list<Node *> constituents=edGetDirectDescendants();
1231   list<InputPort *> ret;
1232   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1233     {
1234       list<InputPort *> currentsPorts=(*iter)->getSetOfInputPort();
1235       ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1236     }
1237   return ret;
1238 }
1239
1240 list<OutputPort *> ComposedNode::getSetOfOutputPort() const
1241 {
1242   list<Node *> constituents=edGetDirectDescendants();
1243   list<OutputPort *> ret;
1244   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1245     {
1246       list<OutputPort *> currentsPorts=(*iter)->getSetOfOutputPort();
1247       ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1248     }
1249   return ret;
1250 }
1251
1252 list<InputDataStreamPort *> ComposedNode::getSetOfInputDataStreamPort() const
1253 {
1254   list<Node *> constituents=edGetDirectDescendants();
1255   list<InputDataStreamPort *> ret;
1256   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1257     {
1258       list<InputDataStreamPort *> currentsPorts=(*iter)->getSetOfInputDataStreamPort();
1259       ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1260     }
1261   return ret;
1262 }
1263
1264 list<OutputDataStreamPort *> ComposedNode::getSetOfOutputDataStreamPort() const
1265 {
1266   list<Node *> constituents=edGetDirectDescendants();
1267   list<OutputDataStreamPort *> ret;
1268   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1269     {
1270       list<OutputDataStreamPort *> currentsPorts=(*iter)->getSetOfOutputDataStreamPort();
1271       ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1272     }
1273   return ret;
1274 }
1275
1276 OutPort *ComposedNode::getOutPort(const std::string& name) const
1277 {
1278   string portName, nodeName;
1279   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false))
1280     {
1281       Node *child = getChildByShortName(nodeName);
1282       return child->getOutPort(portName);
1283     }
1284   else
1285     {
1286       string what("ComposedNode::getOutPort : the port with name "); what+=name; what+=" does not exist on the current level";
1287       throw Exception(what);
1288     }
1289 }
1290
1291 //! Get an input port given its name
1292 /*!
1293  * Contrary to YACS::ENGINE::ComposedNode::getOutputPort, this method is \b NOT recursive 
1294  * and so the leaf of type ElementaryNode aggregating
1295  * this InputPort is directly invoked.
1296  */
1297 InputPort * ComposedNode::getInputPort(const std::string& name) const
1298 {
1299   try {
1300     return Node::getInputPort(name);
1301   }
1302   catch(Exception& e) {}
1303
1304   string portName, nodeName;
1305   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1306     {
1307       Node *child = getChildByName(nodeName);
1308       return child->getInputPort(portName);
1309     }
1310   else
1311     {
1312       string what("ComposedNode::getInputPort : the port with name "); what+=name; what+=" does not exist on the current level";
1313       throw Exception(what);
1314     }
1315 }
1316
1317 //! Get an output port given its name
1318 /*!
1319  * Contrary to YACS::ENGINE::ComposedNode::getInputPort, this method is recursive and go 
1320  * down hierarchy step by step to complete its work.
1321  */
1322 OutputPort * ComposedNode::getOutputPort(const std::string& name) const
1323 {
1324   string portName, nodeName;
1325   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false))
1326     {
1327       Node *child = getChildByShortName(nodeName);
1328       return child->getOutputPort(portName);
1329     }
1330   else
1331     {
1332       string what("ComposedNode::getOutputPort : the port with name "); what+=name; what+=" does not exist on the current level";
1333       throw Exception(what);
1334     }
1335 }
1336
1337 InputDataStreamPort *ComposedNode::getInputDataStreamPort(const std::string& name) const
1338 {
1339   string portName, nodeName;
1340   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1341     {
1342       Node *child = getChildByName(nodeName);
1343       return child->getInputDataStreamPort(portName);
1344     }
1345   else
1346     {
1347       string what("ComposedNode::getInputDataStreamPort : the port with name "); what+=name; what+=" does not exist on the current level";
1348       throw Exception(what);
1349     }
1350 }
1351
1352 OutputDataStreamPort *ComposedNode::getOutputDataStreamPort(const std::string& name) const
1353 {
1354   string portName, nodeName;
1355   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1356     {
1357       Node *child = getChildByName(nodeName);
1358       return child->getOutputDataStreamPort(portName);
1359     }
1360   else
1361     {
1362       string what("ComposedNode::getOutputDataStreamPort : the port with name "); what+=name; what+=" does not exist on the current level";
1363       throw Exception(what);
1364     }
1365 }
1366
1367 //! Update node state on receiving event from a node
1368 /*!
1369  *
1370  * \note Runtime called method. Perform, the state updating, from the son node 'node' 
1371  *       emitting the event 'event' (among Executor static const var).
1372  *         WARNING Precondition : this == node->_father
1373  * \return The event (among Executor static const var) destinated to this->_father node 
1374  *         to perform eventually up level update.
1375  *
1376  * Calls ComposedNode::updateStateOnStartEventFrom if event is YACS::START
1377  *
1378  * Calls ComposedNode::updateStateOnFinishedEventFrom if event is YACS::FINISH
1379  *
1380  * Called by ComposedNode::notifyFrom
1381  */
1382 YACS::Event ComposedNode::updateStateFrom(Node *node,        //* I : node emitting event
1383                                           YACS::Event event, //* I : event emitted
1384                                           const Executor *execInst
1385                                           )
1386 {
1387   DEBTRACE("updateStateFrom: " << node->getName() << " " << event);
1388   try
1389     {
1390       switch(event)
1391         {
1392         case YACS::START:
1393           return updateStateOnStartEventFrom(node);
1394           break;
1395         case YACS::FINISH:
1396           return updateStateOnFinishedEventFrom(node);
1397           break;
1398         case YACS::ABORT:
1399           return updateStateOnFailedEventFrom(node,execInst);
1400           break;
1401         default:
1402           return YACS::NOEVENT;//TODO unexpected type of event
1403           break;
1404         }
1405     }
1406   catch(YACS::Exception& ex)
1407     {
1408       //unexpected exception: probably a bug in engine
1409       //try to keep a consistent global state
1410       DEBTRACE( "updateStateFrom: " << ex.what() );
1411       _errorDetails="Internal error: ";
1412       _errorDetails=_errorDetails + ex.what();
1413       setState(YACS::ERROR);
1414       exForwardFailed();
1415       return YACS::ABORT;
1416     }
1417   catch(...)
1418     {
1419       //unexpected exception: probably a bug in engine
1420       //try to keep a consistent global state
1421       setState(YACS::ERROR);
1422       exForwardFailed();
1423       return YACS::ABORT;
1424     }
1425 }
1426
1427 //! Method used to notify the node that a child node has started
1428 /*!
1429  * Update the ComposedNode state and return the ComposedNode change state 
1430  *
1431  *  \param node : the child node that has started
1432  *  \return the loop state change
1433  */
1434 YACS::Event ComposedNode::updateStateOnStartEventFrom(Node *node)
1435 {
1436   setState(YACS::ACTIVATED);
1437   return YACS::START;
1438 }
1439
1440 //! Method used to notify the node that a child node has failed
1441 YACS::Event ComposedNode::updateStateOnFailedEventFrom(Node *node, const Executor *execInst)
1442 {
1443    setState(YACS::FAILED);
1444    return YACS::ABORT;
1445 }
1446
1447 void ComposedNode::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
1448                                         InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd)
1449 {
1450   if((dynamic_cast<DataFlowPort *>(start) || dynamic_cast<DataFlowPort *>(end))
1451      && (dynamic_cast<DataStreamPort *>(start) || dynamic_cast<DataStreamPort *>(end)))
1452     {//cross protocol required : deeper check needed
1453       bool isOK=false;
1454       list<ComposedNode *>::const_iterator iter;
1455       for(iter=pointsOfViewStart.begin();iter!=pointsOfViewStart.end() && !isOK;iter++)
1456         isOK=(*iter)->isRepeatedUnpredictablySeveralTimes();
1457       for(iter=pointsOfViewEnd.begin();iter!=pointsOfViewEnd.end() && !isOK;iter++)
1458         isOK=(*iter)->isRepeatedUnpredictablySeveralTimes();
1459       if(!isOK)
1460         throw Exception("ComposedNode::checkLinkPossibility : Request for cross protocol link impossible.");
1461     }
1462 }
1463
1464 void ComposedNode::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
1465 {
1466 }
1467
1468 void ComposedNode::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
1469 {
1470 }
1471
1472 void ComposedNode::getDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
1473 {
1474 }
1475
1476 void ComposedNode::getDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
1477 {
1478 }
1479
1480 void ComposedNode::releaseDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
1481 {
1482 }
1483
1484 void ComposedNode::releaseDelegateOf(OutPort *portDwn, OutPort *portUp, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
1485 {
1486 }
1487
1488 void ComposedNode::loaded()
1489 {
1490 }
1491 void ComposedNode::connected()
1492 {
1493 }
1494
1495 void ComposedNode::accept(Visitor *visitor)
1496 {
1497   list<Node *> constituents=edGetDirectDescendants();
1498   for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1499     {
1500       (*iter)->accept(visitor);
1501     }
1502 }
1503
1504 void ComposedNode::setProperty(const std::string& name,const std::string& value)
1505 {
1506   Node::setProperty(name, value);
1507 }
1508
1509 std::string ComposedNode::getProperty(const std::string& name)
1510 {
1511   return Node::getProperty(name);
1512 }
1513
1514
1515 //! redefined on derived class of ComposedNode. by default a ComposedNode has no port by itself
1516 std::list<InputPort *> ComposedNode::getLocalInputPorts() const
1517 {
1518   std::list<InputPort *> lip; return lip; // empty list
1519 }
1520
1521 //! redefined on derived class of ComposedNode. by default a ComposedNode has no port by itself
1522 std::list<OutputPort *> ComposedNode::getLocalOutputPorts() const
1523 {
1524   std::list<OutputPort *> lop; return lop; // empty list
1525 }
1526
1527 bool ComposedNode::isNameAlreadyUsed(const std::string& name) const
1528 {
1529   return false;
1530 }
1531
1532 void ComposedNode::edUpdateState()
1533 {
1534   DEBTRACE("ComposedNode::edUpdateState(): " << _state << " " << _modified);
1535   YACS::StatesForNode state=YACS::READY;
1536
1537   try
1538     {
1539       checkBasicConsistency();
1540       _errorDetails="";
1541     }
1542   catch(Exception& e)
1543     {
1544       state=YACS::INVALID;
1545       _errorDetails=e.what();
1546     }
1547   DEBTRACE("ComposedNode::edUpdateState: " << _errorDetails);
1548
1549   //update children if needed
1550   list<Node *> constituents=edGetDirectDescendants();
1551   for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1552     {
1553       if(!(*iter)->isValid())
1554         state=YACS::INVALID;
1555     }
1556   if(state != _state)
1557     setState(state);
1558   _modified=0;
1559 }
1560
1561 std::string ComposedNode::getErrorReport()
1562 {
1563   DEBTRACE("ComposedNode::getErrorReport: " << getName() << " " << _state);
1564   YACS::StatesForNode effectiveState=getEffectiveState();
1565
1566   if(effectiveState != YACS::INVALID &&  effectiveState != YACS::ERROR && effectiveState != YACS::FAILED)
1567     return "";
1568
1569   std::string report="<error node= " + getName();
1570   switch(effectiveState)
1571     {
1572     case YACS::INVALID:
1573       report=report+" state= INVALID";
1574       break;
1575     case YACS::ERROR:
1576       report=report+" state= ERROR";
1577       break;
1578     case YACS::FAILED:
1579       report=report+" state= FAILED";
1580       break;
1581     default:
1582       break;
1583     }
1584   report=report + ">\n" ;
1585   if(_errorDetails != "")
1586     report=report+_errorDetails+"\n";
1587
1588   list<Node *> constituents=edGetDirectDescendants();
1589   for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1590     {
1591       std::string rep=(*iter)->getErrorReport();
1592       if(rep != "")
1593         {
1594           report=report+rep+"\n";
1595         }
1596     }
1597   report=report+"</error>";
1598   return report;
1599 }
1600
1601
1602
1603 void ComposedNode::checkBasicConsistency() const
1604 {
1605   DEBTRACE("ComposedNode::checkBasicConsistency");
1606   std::list<InputPort *>::const_iterator iter;
1607   std::list<InputPort *> inports=getLocalInputPorts();
1608   for(iter=inports.begin();iter!=inports.end();iter++)
1609     (*iter)->checkBasicConsistency();
1610 }
1611
1612 //! Stop all pending activities of the composed node
1613 /*!
1614  * This method should be called when a Proc is finished and must be deleted from the YACS server
1615  */
1616 void ComposedNode::shutdown(int level)
1617 {
1618   if(level==0)return;
1619   DEBTRACE("ComposedNode::shutdown");
1620   list<Node *> nodes=edGetDirectDescendants();
1621   for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
1622     (*iter)->shutdown(level);
1623 }
1624
1625 //! Clean the composed node in case of not clean exit
1626 /*!
1627  * This method should be called on a control-c or sigterm
1628  */
1629 void ComposedNode::cleanNodes()
1630 {
1631   DEBTRACE("ComposedNode::cleanNodes");
1632   list<Node *> nodes=edGetDirectDescendants();
1633   for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
1634     (*iter)->cleanNodes();
1635 }
1636
1637 //! Reset the state of the node and its children depending on the parameter level
1638 void ComposedNode::resetState(int level)
1639 {
1640   if(level==0)return;
1641
1642   DEBTRACE("ComposedNode::resetState " << level << "," << _state);
1643   if( _state==YACS::ERROR || _state==YACS::FAILED || _state==YACS::ACTIVATED )
1644     {
1645       Node::resetState(level);
1646       std::list<Node *> nodes=edGetDirectDescendants();
1647       for(std::list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
1648         (*iter)->resetState(level);
1649     }
1650 }