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