Salome HOME
7b846bd578f4fc1f18fe50962a11af7cc28d56db
[modules/yacs.git] / src / engine / ComposedNode.cxx
1 // Copyright (C) 2006-2015  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 throw(YACS::Exception)
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) throw(YACS::Exception)
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   while(iterS!=lwstCmnAnctr)
311     {
312       iterS->buildDelegateOf(currentPortI, start, allAscendanceOfNodeStart);
313       iterS=iterS->_father;
314     }
315   bool ret=(pO.first)->addInPort(currentPortI);
316   end->edNotifyReferencedBy(pO.second);
317   return ret;
318 }
319
320 //! Connect an OutPort to an InPort and add the necessary control link
321 /*!
322  * Connect the ports with a data link (edAddLink) and add
323  * a control flow link between the children of the lowest common ancestor node.
324  *
325  * \param start : the OutPort to connect
326  * \param end : the InPort to connect
327  * \return  true if a new link has been created, false otherwise. 
328  */
329 bool ComposedNode::edAddDFLink(OutPort *start, InPort *end) throw(YACS::Exception)
330 {
331   Node* n1=start->getNode();
332   Node* n2=end->getNode();
333   DEBTRACE( n1->getName() << ":" << n2->getName())
334   ComposedNode* father=getLowestCommonAncestor(n1,n2);
335   DEBTRACE( "ComposedNode::edAddDFLink: this="<<this->getName() 
336             << " father=" << father->getName() )
337   DEBTRACE( "ComposedNode::edAddDFLink: OutPort=" << start->getName()
338             << " InPort=" << end->getName() )
339   if (father != this)
340     {
341       bool ret = father->edAddDFLink(start,end); // special treatement for loop
342       return ret;
343     }
344   if(n2 == father)
345     throw Exception("Back link authorized only in special context (loop for example)");
346
347   bool ret= edAddLink(start,end);
348   if(n1 != father)
349     {
350       //add a control link only if nodes are not in the same descendance
351       //if n1 == father (n2 is after n1) : the control link is not needed 
352       //if n2 == father (n1 is after n2) : it's a back link authorized only in loop context
353       while(n1->getFather() != father)
354         n1=n1->getFather();
355       while(n2->getFather() != father)
356         n2=n2->getFather();
357       try
358         {
359           edAddCFLink(n1,n2);
360         }
361       catch (Exception& ex)
362         {
363           // --- remove DF link already created in case of cycle dtection
364           DEBTRACE("Cycle detected, remove CF link");
365           if(start->isAlreadyLinkedWith(end))
366             edRemoveLink(start, end);
367           throw ex;          
368         }
369     }
370   return ret;
371 }
372
373 //! Add a controlflow link between two control ports.
374 /*!
375  * \note Precondition : 'start' AND 'end' are in/outGate contained in a node 
376  *       in DIRECT descendance of 'this'.
377  * \exception Exception : If a cycle has been detected, or incompatibility 
378  *             between input and output, or 'start'/'end' is/are NOT in/outputPort contained 
379  *             in a node in descendance of 'this', or a mutilple link to an input not 
380  *             supporting it.
381  * \return  true if a new link has been created, false otherwise. 
382  */
383 bool ComposedNode::edAddLink(OutGate *start, InGate *end) throw(YACS::Exception)
384 {
385   Node* n1=start->getNode();
386   Node* n2=end->getNode();
387   if(n1==n2)
388     throw Exception("ComposedNode::edAddLink: can not add a control link to a node with itself",1);
389   ComposedNode* father=checkHavingCommonFather(start->getNode(),end->getNode());
390   if(father==0)
391     throw Exception("ComposedNode::edAddLink: Trying to add CF link on orphan nodes.");
392   if(father!=this)
393     {
394       checkInMyDescendance(father);
395       return father->edAddLink(start,end);
396     }
397   bool ret=start->edAddInGate(end);
398   if(ret)
399     try
400       {
401         checkNoCyclePassingThrough(end->getNode());
402       }
403     catch (Exception& ex)
404       {
405         // --- remove  created CF link in case of cycle detection
406         DEBTRACE("Cycle detected, remove CF link");
407         edRemoveCFLink(start->getNode(), end->getNode());
408         throw ex;
409       }
410   return ret;
411 }
412
413 //! Add a controlflow link between two nodes.
414 /*!
415  * Add a controlflow link between two nodes by calling edAddLink on their control ports
416  */
417 bool ComposedNode::edAddCFLink(Node *nodeS, Node *nodeE) throw(YACS::Exception)
418 {
419   return edAddLink(nodeS->getOutGate(),nodeE->getInGate());
420 }
421
422 //! Remove a controlflow link.
423 void ComposedNode::edRemoveCFLink(Node *nodeS, Node *nodeE) throw(YACS::Exception)
424 {
425   edRemoveLink(nodeS->getOutGate(),nodeE->getInGate());
426 }
427
428 //! Remove a dataflow link.
429 /*!
430  * Precondition : 'start' AND 'end' are in/outputPort contained in a node in descendance of 'this'.
431  *
432  * \exception Exception : If the specified link does not exist. The content of Exception 
433  *                        is different in accordance with the link from 'start' to 'end' 
434  *                        implies DF/DS gateway.
435  */
436
437 void ComposedNode::edRemoveLink(OutPort *start, InPort *end) throw(YACS::Exception)
438 {
439   if(!start->isAlreadyLinkedWith(end))
440     throw Exception("ComposedNode::edRemoveLink : unexisting link");
441   ComposedNode* lwstCmnAnctr=getLowestCommonAncestor(start->getNode(),end->getNode());
442   checkInMyDescendance(lwstCmnAnctr);
443   list<ComposedNode *> allAscendanceOfNodeStart=start->getNode()->getAllAscendanceOf(lwstCmnAnctr);
444   list<ComposedNode *> allAscendanceOfNodeEnd=end->getNode()->getAllAscendanceOf(lwstCmnAnctr);
445
446   // --- Part of test if the link from 'start' to 'end' really exist particulary all eventually intermediate ports created
447
448   ComposedNode *iterS=start->getNode()->_father;
449   pair<OutPort *,OutPort *> currentPortO(start,start);
450   vector<pair< ComposedNode * , pair < OutPort* , OutPort *> > > needsToDestroyO;
451
452   Node *nodeOTemp=start->getNode();
453   if(*nodeOTemp<*lwstCmnAnctr)
454     {
455       iterS=nodeOTemp->_father;
456       while(iterS!=lwstCmnAnctr)
457         {
458           if (!iterS)
459             {
460               stringstream what;
461               what << "ComposedNode::edRemoveLink: "
462                    << start->getNode()->getName() << "." <<start->getName() << "->"
463                    << end->getNode()->getName() << "." << end->getName();
464               throw Exception(what.str());
465             }
466           OutPort *tmp=currentPortO.first;
467           iterS->getDelegateOf(currentPortO, end, allAscendanceOfNodeEnd);
468           needsToDestroyO.push_back(pair< ComposedNode * , pair < OutPort* , OutPort *> >(iterS,pair<OutPort* , OutPort *> (tmp,currentPortO.first)));
469           iterS=iterS->_father;
470         }
471     }
472   Node *nodeTemp=end->getNode();
473   InPort * currentPortI=end;
474   if(*nodeTemp<*lwstCmnAnctr)
475     {
476       iterS=nodeTemp->_father;    
477       while(iterS!=lwstCmnAnctr)
478         {
479           if (!iterS)
480             {
481               stringstream what;
482               what << "ComposedNode::edRemoveLink: "
483                    << start->getNode()->getName() << "." <<start->getName() << "->"
484                    << end->getNode()->getName() << "." << end->getName();
485               throw Exception(what.str());
486             }
487           iterS->getDelegateOf(currentPortI, start, allAscendanceOfNodeStart);
488           iterS=iterS->_father;
489         }
490     }
491   // --- End of test for evt intermediate ports created
492   
493   (currentPortO.first)->removeInPort(currentPortI,false);
494   set<OutPort *> repr;
495   (currentPortO.second)->getAllRepresented(repr);
496   if(repr.size()==1)
497     end->edNotifyDereferencedBy(currentPortO.second);
498
499   // --- Performing deletion of intermediate ports
500   
501   iterS=start->getNode()->_father;
502   vector<pair< ComposedNode * , pair < OutPort* , OutPort *> > >::reverse_iterator iter;
503   for(iter=needsToDestroyO.rbegin();iter!=needsToDestroyO.rend();iter++)
504     (*iter).first->releaseDelegateOf(((*iter).second).first, ((*iter).second).second, end,allAscendanceOfNodeEnd);
505   nodeTemp=end->getNode();
506   if(*nodeTemp<*lwstCmnAnctr)
507     {
508       iterS=end->getNode()->_father;
509       currentPortI=end;
510       while(iterS!=lwstCmnAnctr)
511         {
512           iterS->releaseDelegateOf(currentPortI, start, allAscendanceOfNodeStart);
513           iterS=iterS->_father;
514         }
515     }
516 }
517
518 //! Remove a controlflow link.
519 void ComposedNode::edRemoveLink(OutGate *start, InGate *end) throw(YACS::Exception)
520 {
521   ComposedNode* father=checkHavingCommonFather(start->getNode(),end->getNode());
522   if(father!=this)
523     throw Exception("edRemoveLink : nodes not in direct descendance of this");
524   start->edRemoveInGate(end);
525 }
526
527 bool ComposedNode::edAddChild(Node *DISOWNnode) throw(YACS::Exception)
528 {
529   return false; // --- reimplemented in derived classes
530 }
531
532 //! Remove a child node.
533 void ComposedNode::edRemoveChild(Node *node) throw(YACS::Exception)
534 {
535   if(!node)
536     return;
537   if (node->_father!=this)
538     {
539       string what("node "); what+= node->getName() ; what+=" is not a child of node "; what += getName();
540       throw Exception(what);
541     }
542   node->edDisconnectAllLinksWithMe();
543   node->_father = 0;
544   //set _modified flag so edUpdateState() can refresh state
545   modified();
546 }
547
548 //! Splits name globalName in 2 parts using separator.
549 /*!
550  * \note   'priority' specifies if during search process of 'separator' the max part is 
551  *         for 'firstPart' (priority=true) or 'lastPart' (priority=false).
552  *
553  * \throw Exception : 'lastPart' or 'firstPart' is empty.
554  * \return  true if split process succeeds false otherwise (typically when character 
555  *          separator was not found).
556  */
557 bool ComposedNode::splitNamesBySep(const std::string& globalName, const char separator[],
558                                    std::string& firstPart, std::string& lastPart, bool priority) throw(YACS::Exception)
559 {
560   const string delims(separator);
561   string portName, nodeName;
562   string::size_type idx;
563   if(priority)
564     idx = globalName.find_last_of(delims);
565   else
566     idx = globalName.find_first_of(delims);
567   if (idx == string::npos)
568     {
569       firstPart=globalName;
570       lastPart="";
571       return false;
572     }
573   firstPart = globalName.substr(0,idx);
574   lastPart = globalName.substr(idx+1);
575   if ((firstPart.empty()) || (lastPart.empty()))
576     {
577       string what("the name "); what+= globalName ; what+=" is not a valid port name";
578       throw Exception(what);
579     }
580   return true;
581 }
582
583 std::vector< std::pair<OutPort *, InPort *> > ComposedNode::getSetOfInternalLinks() const
584 {
585   vector< pair<OutPort *, InPort *> > ret;
586   list<OutPort *> temp=getSetOfOutPort();
587   for(list<OutPort *>::const_iterator iter2=temp.begin();iter2!=temp.end();iter2++)
588     {
589       set<InPort *> temp2=(*iter2)->edSetInPort();
590       for(set<InPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
591         if(isInMyDescendance((*iter3)->getNode()))
592           ret.push_back(pair<OutPort *, InPort *>((*iter2),(*iter3)));
593     }
594   return ret;
595 }
596
597 std::vector< std::pair<OutPort *, InPort *> > ComposedNode::getSetOfLinksLeavingCurrentScope() const
598 {
599   vector< pair<OutPort *, InPort *> > ret;
600   std::set<OutPort *> ports=getAllOutPortsLeavingCurrentScope();
601   for(set<OutPort *>::iterator iter2=ports.begin();iter2!=ports.end();iter2++)
602     {
603       set<InPort *> temp2=(*iter2)->edSetInPort();
604       for(set<InPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
605         if(!isInMyDescendance((*iter3)->getNode()))
606           ret.push_back(pair<OutPort *, InPort *>(*iter2,*iter3));
607     }
608   return ret;
609 }
610
611 void ComposedNode::checkConsistency(LinkInfo& info) const throw(YACS::Exception)
612 {
613   info.clearAll();
614   info.setPointOfView((ComposedNode *)this);
615   performCFComputations(info);
616   list<InputPort *> setOfInToTest=getSetOfInputPort();
617   for(list<InputPort *>::iterator iter1=setOfInToTest.begin();iter1!=setOfInToTest.end();iter1++)
618     {
619       vector<OutPort *> candidateForAdvCheck;
620       set<OutPort *> outPorts=(*iter1)->edSetOutPort();
621       //Filtering among outPorts, which of them, are candidates to fill *iter1 at the current scope.
622       for(set<OutPort *>::iterator iter2=outPorts.begin();iter2!=outPorts.end();iter2++)
623         {
624           (*iter2)->checkConsistency(info);
625           ComposedNode *manager=getLowestCommonAncestor((*iter2)->getNode(),(*iter1)->getNode());
626           if(isInMyDescendance(manager))
627             candidateForAdvCheck.push_back(*iter2);
628         }
629       if(!candidateForAdvCheck.empty())
630         //End of filtering. Now regarding CF constraints for the current InPutPort.
631         try
632           {
633             checkLinksCoherenceRegardingControl(candidateForAdvCheck,*iter1,info);
634           }
635         catch(YACS::Exception& ex)
636           {
637             std::string what=ex.what();
638             what += "\nfor input port: ";
639             what += (*iter1)->getNode()->getName();
640             what += ".";
641             what += (*iter1)->getName();
642
643             destructCFComputations(info);
644             throw YACS::Exception(what);
645           }
646       else
647         //No backlinks
648         if(!(*iter1)->canBeNull() && !(*iter1)->edIsManuallyInitialized())
649           info.pushErrLink(0,*iter1,E_NEVER_SET_INPUTPORT);
650     }
651   destructCFComputations(info);
652 }
653
654 /*!
655  * This method check that G1 <- G2 <- G3 <- G1 does not happened.
656  * Typically called by methods that set a hierarchy (Bloc::edAddChild, Loop::edSetNode, ...).
657  */
658 void ComposedNode::checkNoCrossHierachyWith(Node *node) const throw(YACS::Exception)
659 {
660   ComposedNode *nodeC=dynamic_cast<ComposedNode *>(node);
661   if(!nodeC)
662     return ;
663   list<ComposedNode *> ascendants=getAllAscendanceOf();
664   if(find(ascendants.begin(),ascendants.end(),nodeC)!=ascendants.end())
665     {
666       const char what[]="ComposedNode::checkNoCrossHierachyWith : ComposedNode with name \"";
667       string stream(what); stream+=node->getName(); stream+="\" is already in hierarchy ascendance of node with name \"";
668       stream+=_name; stream+="\" ; So it can't be now in its descendance !";
669       throw Exception(stream);
670     }
671 }
672
673 //! perform \b recursively all CF computations.
674 void ComposedNode::performCFComputations(LinkInfo& info) const
675 {
676   list<Node *> nodes=edGetDirectDescendants();
677   for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
678     if(dynamic_cast<ComposedNode *>(*iter))
679       ((ComposedNode *)(*iter))->performCFComputations(info);
680 }
681
682 //! destroy \b recursively all results of initial computations.
683 void ComposedNode::destructCFComputations(LinkInfo& info) const
684 {
685   list<Node *> nodes=edGetDirectDescendants();
686   for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
687     if(dynamic_cast<ComposedNode *>(*iter))
688       ((ComposedNode *)(*iter))->destructCFComputations(info);
689 }
690
691 /*!
692  * Returns the lowest Node (Elementary or Composed) (is sense of hierachy level ( operator< ) ) containing all 'ports'.
693  * Typically use in consistency computation.
694  * Precondition : 'ports' \b must contain at least one element. All elements of 'ports' should be in descendance of 'this'.
695  */
696 Node *ComposedNode::getLowestNodeDealingAll(const std::list<OutPort *>& ports) const
697 {
698   list< OutPort *>::const_iterator iter=ports.begin();
699   Node *ret=(*iter)->getNode();
700   iter++;
701   for(;iter!=ports.end();iter++)
702     {
703       Node *tmp=(*iter)->getNode();
704       if(*tmp>*ret)
705         ret=tmp;
706     }
707   return ret;
708 }
709
710 /*!
711  * call it only for 'starts' to 'end' links \b DEALED by 'this'.
712  */
713 void ComposedNode::checkLinksCoherenceRegardingControl(const std::vector<OutPort *>& starts, InputPort *end, LinkInfo& info) const throw(YACS::Exception)
714 {
715   map < ComposedNode *, list<OutPort *>, SortHierarc > outputs;//forward link classical
716   vector<OutPort *> outputsCross;//forward link cross
717   map < ComposedNode *, list<OutPort *>, SortHierarc > outputsBw;//backward
718   vector<OutPort *>::const_iterator iter1;
719   //vector<DataPort *> history=((*iter1).second)[0]->calculateHistoryOfLinkWith(end);
720   //DataPort *cross=DataPort::isCrossingType(history);
721   for(iter1=starts.begin();iter1!=starts.end();iter1++)
722     {
723       ComposedNode *manager=getLowestCommonAncestor((*iter1)->getNode(),end->getNode());
724       manager->checkControlDependancy((*iter1), end, false, outputs, outputsCross, outputsBw, info);
725     }
726   //Ok now let's regarding outputs all combinations : (outputs.size())*(outputs.size()-1)/2
727   unsigned char isAlreadyFed=FREE_ST;
728   //Dealing excusively with DS. Level is useless here because simultaneity is required for DS.
729   if(outputsCross.size()>0)
730     {
731       isAlreadyFed=FED_DS_ST;
732       if(outputsCross.size()>1)
733         for(vector< OutPort *>::const_iterator iter1=outputsCross.begin();iter1!=(outputsCross.end()-2);iter1++)
734           info.pushErrLink(*iter1,end,E_COLLAPSE_DS);
735     }
736   map < ComposedNode *, list<OutPort *>, SortHierarc >::iterator iter3=outputs.begin();
737   for(;iter3!=outputs.end();iter3++)
738     ((*iter3).first)->checkCFLinks((*iter3).second,end,isAlreadyFed,true,info);
739   if(isAlreadyFed==FREE_ST)
740     if(!end->edIsManuallyInitialized())
741       info.pushErrLink(0,end,E_ONLY_BACKWARD_DEFINED);
742   isAlreadyFed=FREE_ST;
743   //
744   map < ComposedNode *, list<OutPort *>, SortHierarc >::reverse_iterator iter5=outputsBw.rbegin();
745   for(;iter5!=outputsBw.rend();iter5++)
746     ((*iter5).first)->checkCFLinks((*iter5).second,end,isAlreadyFed,false,info);
747 }
748
749 /*!
750  * Internal method during CF links. This methode is in charge to statuate on links consistency in the case 
751  * that no control flow defined by user is set.
752  */
753 void ComposedNode::solveObviousOrDelegateCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
754 {
755   static const char what[]="ComposedNode::solveObviousOrDelegateCFLinks : Internal error occured - uncorrect hierarchy detected !";
756   if(starts.size()==1)
757     {
758       if(alreadyFed==FREE_ST)
759         {
760           if(!direction)
761             info.pushInfoLink(*(starts.begin()),end,I_BACK);
762           alreadyFed=FED_ST;
763         }
764       else if(alreadyFed==FED_ST)
765         info.pushInfoLink(*(starts.begin()),end,direction ?  I_USELESS : I_BACK_USELESS);
766       else
767         info.pushErrLink(*(starts.begin()),end,E_COLLAPSE_DFDS);
768     }
769   else
770     {
771       Node *levelOfDecision=getLowestNodeDealingAll(starts);
772       if(levelOfDecision==this)
773         throw Exception(what);
774       if(dynamic_cast<ElementaryNode *>(levelOfDecision))
775         {
776           WarnReason reason;
777           if(alreadyFed==FREE_ST || alreadyFed==FED_ST)
778             {
779               if(alreadyFed==FREE_ST)
780                 {
781                   reason=direction ? W_COLLAPSE_EL : W_BACK_COLLAPSE_EL;
782                   alreadyFed=FED_ST;
783                 }
784               else
785                 reason=direction ? W_COLLAPSE_EL_AND_USELESS : W_BACK_COLLAPSE_EL_AND_USELESS;
786               for(list< OutPort *>::const_iterator iter=starts.begin();iter!=starts.end();iter++)
787                 info.pushWarnLink(*iter,end,reason);
788             }
789         }
790       else
791         ((ComposedNode *)levelOfDecision)->checkCFLinks(starts,end,alreadyFed,direction,info);
792     }
793 }
794
795 //! check control flow links
796 /*!
797  * \param starts If different of 0, must aggregate at leat \b 1 element.
798  * \param end :
799  * \param alreadyFed in/out parameter. Indicates if 'end' ports is already and surely set or fed by an another port.
800  * \param direction If true : forward direction else backward direction.
801  * \param info : informations collectedduring the check
802  */
803 void ComposedNode::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
804 {
805   static const char what[]="ComposedNode::checkCFLinks : Internal error occured - uncorrect hierarchy detected !";
806   Node *nodeEnd=isInMyDescendance(end->getNode());
807   if(!nodeEnd)
808     return solveObviousOrDelegateCFLinks(starts,end,alreadyFed,direction,info);
809   //This case is typically dedicated when direct son is ElementaryNode and self link is defined on this.
810   if(!dynamic_cast<ElementaryNode *>(nodeEnd))
811     throw Exception(what);
812
813   list< OutPort *>::const_iterator iter=starts.begin();
814   Node *nodeStart=(*iter)->getNode();
815   iter++;
816   if(nodeEnd!=nodeStart)
817     throw Exception(what);
818
819   for(;iter!=starts.end();iter++)
820     if((*iter)->getNode()!=nodeStart)
821       throw Exception(what);
822   //Ok at this step we are sure that we have back links on the same elementary node.
823   if(starts.size()>1)
824     for(iter=starts.begin();iter!=starts.end();iter++)
825       info.pushWarnLink(*iter,end,W_BACK_COLLAPSE_EL);
826   else//here no need to look at 'alreadyFed' var because it is waranteed to be equal to FREE_ST by construction.
827     info.pushInfoLink(*(starts.begin()),end,I_BACK);
828   alreadyFed=FED_ST;
829 }
830
831 std::vector< std::pair<InPort *, OutPort *> > ComposedNode::getSetOfLinksComingInCurrentScope() const
832 {
833   vector< pair<InPort *, OutPort *> > ret;
834   set<InPort *> ports=getAllInPortsComingFromOutsideOfCurrentScope();
835   for(set<InPort *>::iterator iter2=ports.begin();iter2!=ports.end();iter2++)
836     {
837       set<OutPort *> temp2=(*iter2)->edSetOutPort();
838       for(set<OutPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
839         {
840           if(isInMyDescendance((*iter3)->getNode()))continue;
841           std::set<OutPort *> trueOutPorts;
842           (*iter3)->getAllRepresented(trueOutPorts);
843           for(std::set<OutPort *>::iterator iter4=trueOutPorts.begin();iter4!=trueOutPorts.end();++iter4)
844             ret.push_back(pair<InPort *, OutPort *>(*iter2,*iter4));
845         }
846     }
847   return ret;
848 }
849
850 //! List all output ports of children nodes that are linked to out of scope input ports
851 /*!
852  * \note List all output ports of nodes sons of 'this' that are linked to input ports 
853  *       of nodes not in descendance of 'this'.
854  *       This method contrary to getAllInPortsComingFromOutsideOfCurrentScope is NOT virtual 
855  *       because for the moment all daughter classes have no more hidden YACS::ENGINE::OutPort.
856  */
857 std::set<OutPort *> ComposedNode::getAllOutPortsLeavingCurrentScope() const
858 {
859   set<OutPort *> ret;
860   list<OutPort *> temp=getSetOfOutPort();
861   for(list<OutPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
862     {
863       set<InPort *> temp2=(*iter2)->edSetInPort();
864       for(set<InPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
865         if(!isInMyDescendance((*iter3)->getNode()))
866           {
867             ret.insert(*iter2);
868             break;
869           }
870     }
871   return ret;
872 }
873
874 //! List all input ports that are linked to out of scope ports
875 /*!
876  *
877  * List all input ports of 'this' so that, for each it exists at least 1 link coming 
878  * from outside to it.
879  *
880  */
881 std::set<InPort *> ComposedNode::getAllInPortsComingFromOutsideOfCurrentScope() const
882 {
883   set<InPort *> ret;
884   list<InPort *> temp=getSetOfInPort();
885   for(list<InPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
886     {
887       set<OutPort *> temp2=(*iter2)->edSetOutPort();
888       for(set<OutPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
889         if(*iter3)
890           if(!isInMyDescendance((*iter3)->getNode()))
891             {
892               ret.insert(*iter2);
893               break;
894             }
895     }
896   return ret;
897 }
898
899 void ComposedNode::edDisconnectAllLinksWithMe()
900 {
901   //CF
902   DEBTRACE("-");
903   Node::edDisconnectAllLinksWithMe();
904   //Leaving part
905   DEBTRACE("--");
906   vector< pair<OutPort *, InPort *> > linksToDestroy=getSetOfLinksLeavingCurrentScope();
907   vector< pair<OutPort *, InPort *> >::iterator iter;
908   for(iter=linksToDestroy.begin();iter!=linksToDestroy.end();iter++)
909     {
910       DEBTRACE("---");
911       (*iter).first->removeInPort((*iter).second,true);
912     }
913   //Arriving part
914   vector< pair<InPort *, OutPort *> > linksToDestroy2=getSetOfLinksComingInCurrentScope();
915   vector< pair<InPort *, OutPort *> >::iterator iter2;
916   for(iter2=linksToDestroy2.begin();iter2!=linksToDestroy2.end();iter2++)
917     {
918       DEBTRACE("----");
919       (*iter2).second->removeInPort((*iter2).first,true);
920     }
921 }
922
923 ComposedNode *ComposedNode::getRootNode() const throw(YACS::Exception)
924 {
925   if(!_father)
926     return (ComposedNode *)this;
927   return Node::getRootNode();
928 }
929
930 //! Check that Node 'node' is already a direct son of this.
931 bool ComposedNode::isNodeAlreadyAggregated(const Node *node) const
932 {
933   list<ComposedNode *> nodeAncestors = node->getAllAscendanceOf();
934   return find(nodeAncestors.begin(),nodeAncestors.end(),(ComposedNode *)this)!=nodeAncestors.end();
935 }
936
937 //! Returns the parent of a node that is the direct child of this node 
938 /*!
939  * \note if 'nodeToTest'=='this' this is returned. Else if 'nodeToTest' is in descendance of
940  *       'this' the direct son is returned. 
941  *       Else 0 is returned. 
942  *
943  * \param nodeToTest : the node to check
944  */
945 Node *ComposedNode::isInMyDescendance(Node *nodeToTest) const
946 {
947   if(nodeToTest==0)
948     return 0;
949   if((ComposedNode *)nodeToTest==this)
950     return (Node *)this;
951   Node *iterBack=nodeToTest;
952   ComposedNode *iter=nodeToTest->_father;
953   while(iter!=0 && iter!=this)
954     {
955       iterBack=iter;
956       iter=iter->_father;
957     }
958   if(iter!=0)
959     return iterBack;
960   else
961     return 0;
962 }
963
964 string ComposedNode::getChildName(const Node* node) const throw(YACS::Exception)
965 {
966   string nodeName=node->getQualifiedName();    
967   if (!isNodeAlreadyAggregated(node))
968     {
969       if (node->getName() == "thisIsAFakeNode")
970         {
971           string child = node->getName()+".thisIsAFakeNode";
972           return child;
973         }
974       else
975         {
976           string what("node "); what+= node->getName() ; what+=" is not a child of node "; what += getName();
977           throw Exception(what);
978         }
979     }
980   
981   const Node *father = node->_father;
982   while (father != this)
983     {
984       nodeName = father->getQualifiedName() + SEP_CHAR_BTW_LEVEL + nodeName;
985       father = father->_father;
986     }
987   return nodeName;
988 }
989
990 std::string ComposedNode::getMyQualifiedName(const Node *directSon) const
991 {
992   return directSon->getName();
993 }
994
995 Node *ComposedNode::getChildByName(const std::string& name) const throw(YACS::Exception)
996 {
997   string potentiallyDirectSonName, remainsPath;
998   bool forwardNeeded=ComposedNode::splitNamesBySep(name, SEP_CHAR_BTW_LEVEL,
999                                                    potentiallyDirectSonName,remainsPath,false);
1000   Node *child=getChildByShortName(potentiallyDirectSonName);
1001   if(!forwardNeeded)
1002     return child;
1003   else
1004     return child->getChildByName(remainsPath);
1005 }
1006
1007 //! Check if a node is in the descendance of this node
1008 /*!
1009  * \note Check that 'nodeToTest' is in descendance of 'this' OR equal to 'this'
1010  * \exception Exception : If 'nodeToTest' is NOT in descendance of 'this' AND not equal to 'this'
1011  * \param nodeToTest : the node to check
1012  */
1013 void ComposedNode::checkInMyDescendance(Node *nodeToTest) const throw(YACS::Exception)
1014 {
1015   const char whatC[]=" is not the descendance of node ";
1016   if(nodeToTest==0)
1017     {
1018       string what("node "); what+= nodeToTest->getName(); what+=" ";
1019       what+=whatC; what+=_name;
1020       throw Exception(what);
1021     }
1022   if((ComposedNode *)nodeToTest==this)
1023     return;
1024   ComposedNode *iter=nodeToTest->_father;
1025   while(iter!=0 && iter!=this)
1026     iter=iter->_father;
1027   if(iter==0)
1028     {
1029       string what("node "); what+= nodeToTest->getName(); what+=" ";
1030       what+=whatC; what+=_name;
1031       throw Exception(what);
1032     }
1033 }
1034
1035 //! Retrieves the lowest common ancestor of 2 nodes
1036 /*!
1037  * 
1038  * \note Retrieves the lowest common ancestor of 'node1' AND 'node2'. 
1039  *       If  'node1' or 'node2' are both or indiscriminately instances of ComposedNode and that
1040  *       'node1' is in descendance of 'node2' (resp. 'node2' in descendance of 'node1')
1041  *       'node2' is returned (resp. 'node1').
1042  * \exception Exception : if 'node1' and 'node2' do not share the same genealogy.
1043  * \return The lowest common ancestor if it exists.
1044  *
1045  */
1046 ComposedNode *ComposedNode::getLowestCommonAncestor(Node *node1, Node *node2) throw(YACS::Exception)
1047 {
1048   const char what[]="The two nodes do not share the same genealogy";
1049   if(node1==0 || node2==0)
1050     throw Exception(what);
1051   ComposedNode *temp;
1052   if(dynamic_cast<ComposedNode *>(node1))
1053     temp=(ComposedNode *)node1;//->_father;
1054   else
1055     temp=(ComposedNode *)node1->_father;
1056   set<ComposedNode *> s;
1057   while(temp)
1058     {
1059       s.insert(temp);
1060       temp=temp->_father;
1061     }
1062   //
1063   if(dynamic_cast<ComposedNode *>(node2))
1064     temp=(ComposedNode *)node2;//->_father;
1065   else
1066     temp=(ComposedNode *)node2->_father;
1067   set<ComposedNode *>::iterator iter=s.find(temp);
1068   while(temp && iter==s.end())
1069     {
1070       iter=s.find(temp);
1071       temp=temp->_father;
1072     }
1073   if(iter==s.end())
1074     throw Exception(what);
1075   return *iter;
1076 }
1077
1078 /*!
1079  * Same as getLowestCommonAncestor method except that absolute string representation is considered here instead of instances.
1080  */
1081 std::string ComposedNode::getLowestCommonAncestorStr(const std::string& node1, const std::string& node2)
1082 {
1083   std::string ret;
1084   std::size_t it1_b(0),it1_e(0),it2_b(0),it2_e(0);
1085   while(it1_b!=std::string::npos && it2_b!=std::string::npos)
1086     {
1087       it1_e=node1.find(SEP_CHAR_BTW_LEVEL,it1_b);
1088       it2_e=node2.find(SEP_CHAR_BTW_LEVEL,it2_b);
1089       if(it1_e!=it2_e && it1_e!=std::string::npos && it2_e!=std::string::npos)
1090         break;
1091       std::string elt1(node1.substr(it1_b,it1_e-it1_b)),elt2(node2.substr(it2_b,it2_e-it2_b));
1092       if(elt1!=elt2)
1093         break;
1094       if(!ret.empty())
1095         ret+=SEP_CHAR_BTW_LEVEL;
1096       ret+=elt1;
1097       it1_b=node1.find_first_not_of(SEP_CHAR_BTW_LEVEL,it1_e);
1098       it2_b=node2.find_first_not_of(SEP_CHAR_BTW_LEVEL,it2_e);
1099     }
1100   return ret;
1101 }
1102
1103 list<ElementaryNode *> ComposedNode::getRecursiveConstituents() const
1104 {
1105   list<ElementaryNode *> ret;
1106   list<Node *> setOfNode=edGetDirectDescendants();
1107   for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1108     {
1109       list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
1110       ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1111     }
1112   return ret;
1113 }
1114
1115 //! Idem getAllRecursiveNodes, but this node is NOT included.
1116 list<Node *> ComposedNode::getAllRecursiveConstituents()
1117 {
1118   list<Node *> ret;
1119   list<Node *> setOfNode=edGetDirectDescendants();
1120   for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1121     {
1122       if ( dynamic_cast<ComposedNode*> (*iter) )
1123         {
1124           list<Node *> myCurrentSet=((ComposedNode*)(*iter))->getAllRecursiveConstituents();
1125           ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1126           ret.push_back(*iter);
1127         }
1128       else
1129         {
1130           list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
1131           ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1132         }
1133     }
1134   return ret;
1135 }
1136
1137 //! Get all children nodes  elementary and composed including this node
1138 list<Node *> ComposedNode::getAllRecursiveNodes()
1139 {
1140   list<Node *> ret;
1141   list<Node *> setOfNode=edGetDirectDescendants();
1142   for(list<Node *>::iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1143     {
1144       if ( dynamic_cast<ElementaryNode*> (*iter) )
1145         {
1146           list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
1147           ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1148         }
1149       else
1150         {
1151           list<Node *> myCurrentSet=((ComposedNode*)(*iter))->getAllRecursiveNodes();
1152           ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1153         }
1154     }
1155   ret.push_back(this);
1156   return ret;
1157 }
1158
1159
1160 //! Get the progress weight for all elementary nodes
1161 /*!
1162  * Only elementary nodes have weight. A simple composed node only sum up weight of all his descendants
1163  * (working is different for loop or switch nodes)
1164  */
1165 list<ProgressWeight> ComposedNode::getProgressWeight() const
1166 {
1167   list<ProgressWeight> ret;
1168   list<Node *> setOfNode=edGetDirectDescendants();
1169   for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1170     {
1171       list<ProgressWeight> myCurrentSet=((ComposedNode*)(*iter))->getProgressWeight();
1172       ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1173     }
1174   return ret;
1175 }
1176
1177 //! Get the input port name 
1178 /*!
1179  * get the input port name used by the current node, recursively built with children names.
1180  */
1181
1182 string ComposedNode::getInPortName(const InPort * inPort) const throw(YACS::Exception)
1183 {
1184   return getPortName<InPort>(inPort);
1185 }
1186
1187 string ComposedNode::getOutPortName(const OutPort *outPort) const throw(YACS::Exception)
1188 {
1189   return getPortName<OutPort>(outPort);
1190 }
1191
1192 int ComposedNode::getNumberOfInputPorts() const
1193 {
1194   list<Node *> constituents=edGetDirectDescendants();
1195   int ret=0;
1196   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1197     ret+=(*iter)->getNumberOfInputPorts();
1198   return ret;
1199 }
1200
1201 int ComposedNode::getNumberOfOutputPorts() const
1202 {
1203   list<Node *> constituents=edGetDirectDescendants();
1204   int ret=0;
1205   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1206     ret+=(*iter)->getNumberOfOutputPorts();
1207   return ret;
1208 }
1209
1210 list<InputPort *> ComposedNode::getSetOfInputPort() const
1211 {
1212   list<Node *> constituents=edGetDirectDescendants();
1213   list<InputPort *> ret;
1214   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1215     {
1216       list<InputPort *> currentsPorts=(*iter)->getSetOfInputPort();
1217       ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1218     }
1219   return ret;
1220 }
1221
1222 list<OutputPort *> ComposedNode::getSetOfOutputPort() const
1223 {
1224   list<Node *> constituents=edGetDirectDescendants();
1225   list<OutputPort *> ret;
1226   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1227     {
1228       list<OutputPort *> currentsPorts=(*iter)->getSetOfOutputPort();
1229       ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1230     }
1231   return ret;
1232 }
1233
1234 list<InputDataStreamPort *> ComposedNode::getSetOfInputDataStreamPort() const
1235 {
1236   list<Node *> constituents=edGetDirectDescendants();
1237   list<InputDataStreamPort *> ret;
1238   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1239     {
1240       list<InputDataStreamPort *> currentsPorts=(*iter)->getSetOfInputDataStreamPort();
1241       ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1242     }
1243   return ret;
1244 }
1245
1246 list<OutputDataStreamPort *> ComposedNode::getSetOfOutputDataStreamPort() const
1247 {
1248   list<Node *> constituents=edGetDirectDescendants();
1249   list<OutputDataStreamPort *> ret;
1250   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1251     {
1252       list<OutputDataStreamPort *> currentsPorts=(*iter)->getSetOfOutputDataStreamPort();
1253       ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1254     }
1255   return ret;
1256 }
1257
1258 OutPort *ComposedNode::getOutPort(const std::string& name) const throw(YACS::Exception)
1259 {
1260   string portName, nodeName;
1261   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false))
1262     {
1263       Node *child = getChildByShortName(nodeName);
1264       return child->getOutPort(portName);
1265     }
1266   else
1267     {
1268       string what("ComposedNode::getOutPort : the port with name "); what+=name; what+=" does not exist on the current level";
1269       throw Exception(what);
1270     }
1271 }
1272
1273 //! Get an input port given its name
1274 /*!
1275  * Contrary to YACS::ENGINE::ComposedNode::getOutputPort, this method is \b NOT recursive 
1276  * and so the leaf of type ElementaryNode aggregating
1277  * this InputPort is directly invoked.
1278  */
1279 InputPort * ComposedNode::getInputPort(const std::string& name) const throw(YACS::Exception)
1280 {
1281   try {
1282     return Node::getInputPort(name);
1283   }
1284   catch(Exception& e) {}
1285
1286   string portName, nodeName;
1287   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1288     {
1289       Node *child = getChildByName(nodeName);
1290       return child->getInputPort(portName);
1291     }
1292   else
1293     {
1294       string what("ComposedNode::getInputPort : the port with name "); what+=name; what+=" does not exist on the current level";
1295       throw Exception(what);
1296     }
1297 }
1298
1299 //! Get an output port given its name
1300 /*!
1301  * Contrary to YACS::ENGINE::ComposedNode::getInputPort, this method is recursive and go 
1302  * down hierarchy step by step to complete its work.
1303  */
1304 OutputPort * ComposedNode::getOutputPort(const std::string& name) const throw(YACS::Exception)
1305 {
1306   string portName, nodeName;
1307   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false))
1308     {
1309       Node *child = getChildByShortName(nodeName);
1310       return child->getOutputPort(portName);
1311     }
1312   else
1313     {
1314       string what("ComposedNode::getOutputPort : the port with name "); what+=name; what+=" does not exist on the current level";
1315       throw Exception(what);
1316     }
1317 }
1318
1319 InputDataStreamPort *ComposedNode::getInputDataStreamPort(const std::string& name) const throw(YACS::Exception)
1320 {
1321   string portName, nodeName;
1322   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1323     {
1324       Node *child = getChildByName(nodeName);
1325       return child->getInputDataStreamPort(portName);
1326     }
1327   else
1328     {
1329       string what("ComposedNode::getInputDataStreamPort : the port with name "); what+=name; what+=" does not exist on the current level";
1330       throw Exception(what);
1331     }
1332 }
1333
1334 OutputDataStreamPort *ComposedNode::getOutputDataStreamPort(const std::string& name) const throw(YACS::Exception)
1335 {
1336   string portName, nodeName;
1337   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1338     {
1339       Node *child = getChildByName(nodeName);
1340       return child->getOutputDataStreamPort(portName);
1341     }
1342   else
1343     {
1344       string what("ComposedNode::getOutputDataStreamPort : the port with name "); what+=name; what+=" does not exist on the current level";
1345       throw Exception(what);
1346     }
1347 }
1348
1349 //! Update node state on receiving event from a node
1350 /*!
1351  *
1352  * \note Runtime called method. Perform, the state updating, from the son node 'node' 
1353  *       emitting the event 'event' (among Executor static const var).
1354  *         WARNING Precondition : this == node->_father
1355  * \return The event (among Executor static const var) destinated to this->_father node 
1356  *         to perform eventually up level update.
1357  *
1358  * Calls ComposedNode::updateStateOnStartEventFrom if event is YACS::START
1359  *
1360  * Calls ComposedNode::updateStateOnFinishedEventFrom if event is YACS::FINISH
1361  *
1362  * Called by ComposedNode::notifyFrom
1363  */
1364 YACS::Event ComposedNode::updateStateFrom(Node *node,        //* I : node emitting event
1365                                           YACS::Event event,  //* I : event emitted
1366                                           const Executor *execInst
1367                                           )
1368 {
1369   DEBTRACE("updateStateFrom: " << node->getName() << " " << event);
1370   try
1371     {
1372       switch(event)
1373         {
1374         case YACS::START:
1375           return updateStateOnStartEventFrom(node);
1376           break;
1377         case YACS::FINISH:
1378           return updateStateOnFinishedEventFrom(node);
1379           break;
1380         case YACS::ABORT:
1381           return updateStateOnFailedEventFrom(node,execInst);
1382           break;
1383         default:
1384           return YACS::NOEVENT;//TODO unexpected type of event
1385           break;
1386         }
1387     }
1388   catch(YACS::Exception& ex)
1389     {
1390       //unexpected exception: probably a bug in engine
1391       //try to keep a consistent global state
1392       DEBTRACE( "updateStateFrom: " << ex.what() );
1393       _errorDetails="Internal error: ";
1394       _errorDetails=_errorDetails + ex.what();
1395       setState(YACS::ERROR);
1396       exForwardFailed();
1397       return YACS::ABORT;
1398     }
1399   catch(...)
1400     {
1401       //unexpected exception: probably a bug in engine
1402       //try to keep a consistent global state
1403       setState(YACS::ERROR);
1404       exForwardFailed();
1405       return YACS::ABORT;
1406     }
1407 }
1408
1409 //! Method used to notify the node that a child node has started
1410 /*!
1411  * Update the ComposedNode state and return the ComposedNode change state 
1412  *
1413  *  \param node : the child node that has started
1414  *  \return the loop state change
1415  */
1416 YACS::Event ComposedNode::updateStateOnStartEventFrom(Node *node)
1417 {
1418   setState(YACS::ACTIVATED);
1419   return YACS::START;
1420 }
1421
1422 //! Method used to notify the node that a child node has failed
1423 YACS::Event ComposedNode::updateStateOnFailedEventFrom(Node *node, const Executor *execInst)
1424 {
1425    setState(YACS::FAILED);
1426    return YACS::ABORT;
1427 }
1428
1429 void ComposedNode::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
1430                                         InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(YACS::Exception)
1431 {
1432   if((dynamic_cast<DataFlowPort *>(start) || dynamic_cast<DataFlowPort *>(end))
1433      && (dynamic_cast<DataStreamPort *>(start) || dynamic_cast<DataStreamPort *>(end)))
1434     {//cross protocol required : deeper check needed
1435       bool isOK=false;
1436       list<ComposedNode *>::const_iterator iter;
1437       for(iter=pointsOfViewStart.begin();iter!=pointsOfViewStart.end() && !isOK;iter++)
1438         isOK=(*iter)->isRepeatedUnpredictablySeveralTimes();
1439       for(iter=pointsOfViewEnd.begin();iter!=pointsOfViewEnd.end() && !isOK;iter++)
1440         isOK=(*iter)->isRepeatedUnpredictablySeveralTimes();
1441       if(!isOK)
1442         throw Exception("ComposedNode::checkLinkPossibility : Request for cross protocol link impossible.");
1443     }
1444 }
1445
1446 void ComposedNode::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
1447 {
1448 }
1449
1450 void ComposedNode::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
1451 {
1452 }
1453
1454 void ComposedNode::getDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
1455 {
1456 }
1457
1458 void ComposedNode::getDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
1459 {
1460 }
1461
1462 void ComposedNode::releaseDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
1463 {
1464 }
1465
1466 void ComposedNode::releaseDelegateOf(OutPort *portDwn, OutPort *portUp, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
1467 {
1468 }
1469
1470 void ComposedNode::loaded()
1471 {
1472 }
1473 void ComposedNode::connected()
1474 {
1475 }
1476
1477 void ComposedNode::accept(Visitor *visitor)
1478 {
1479   list<Node *> constituents=edGetDirectDescendants();
1480   for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1481     {
1482       (*iter)->accept(visitor);
1483     }
1484 }
1485
1486 //! redefined on derived class of ComposedNode. by default a ComposedNode has no port by itself
1487 std::list<InputPort *> ComposedNode::getLocalInputPorts() const
1488 {
1489   std::list<InputPort *> lip; return lip; // empty list
1490 }
1491
1492 //! redefined on derived class of ComposedNode. by default a ComposedNode has no port by itself
1493 std::list<OutputPort *> ComposedNode::getLocalOutputPorts() const
1494 {
1495   std::list<OutputPort *> lop; return lop; // empty list
1496 }
1497
1498 bool ComposedNode::isNameAlreadyUsed(const std::string& name) const
1499 {
1500   return false;
1501 }
1502
1503 void ComposedNode::edUpdateState()
1504 {
1505   DEBTRACE("ComposedNode::edUpdateState(): " << _state << " " << _modified);
1506   YACS::StatesForNode state=YACS::READY;
1507
1508   try
1509     {
1510       checkBasicConsistency();
1511       _errorDetails="";
1512     }
1513   catch(Exception& e)
1514     {
1515       state=YACS::INVALID;
1516       _errorDetails=e.what();
1517     }
1518   DEBTRACE("ComposedNode::edUpdateState: " << _errorDetails);
1519
1520   //update children if needed
1521   list<Node *> constituents=edGetDirectDescendants();
1522   for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1523     {
1524       if(!(*iter)->isValid())
1525         state=YACS::INVALID;
1526     }
1527   if(state != _state)
1528     setState(state);
1529   _modified=0;
1530 }
1531
1532 std::string ComposedNode::getErrorReport()
1533 {
1534   DEBTRACE("ComposedNode::getErrorReport: " << getName() << " " << _state);
1535   YACS::StatesForNode effectiveState=getEffectiveState();
1536
1537   if(effectiveState != YACS::INVALID &&  effectiveState != YACS::ERROR && effectiveState != YACS::FAILED)
1538     return "";
1539
1540   std::string report="<error node= " + getName();
1541   switch(effectiveState)
1542     {
1543     case YACS::INVALID:
1544       report=report+" state= INVALID";
1545       break;
1546     case YACS::ERROR:
1547       report=report+" state= ERROR";
1548       break;
1549     case YACS::FAILED:
1550       report=report+" state= FAILED";
1551       break;
1552     default:
1553       break;
1554     }
1555   report=report + ">\n" ;
1556   if(_errorDetails != "")
1557     report=report+_errorDetails+"\n";
1558
1559   list<Node *> constituents=edGetDirectDescendants();
1560   for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1561     {
1562       std::string rep=(*iter)->getErrorReport();
1563       if(rep != "")
1564         {
1565           report=report+rep+"\n";
1566         }
1567     }
1568   report=report+"</error>";
1569   return report;
1570 }
1571
1572
1573
1574 void ComposedNode::checkBasicConsistency() const throw(YACS::Exception)
1575 {
1576   DEBTRACE("ComposedNode::checkBasicConsistency");
1577   std::list<InputPort *>::const_iterator iter;
1578   std::list<InputPort *> inports=getLocalInputPorts();
1579   for(iter=inports.begin();iter!=inports.end();iter++)
1580     (*iter)->checkBasicConsistency();
1581 }
1582
1583 //! Stop all pending activities of the composed node
1584 /*!
1585  * This method should be called when a Proc is finished and must be deleted from the YACS server
1586  */
1587 void ComposedNode::shutdown(int level)
1588 {
1589   if(level==0)return;
1590   DEBTRACE("ComposedNode::shutdown");
1591   list<Node *> nodes=edGetDirectDescendants();
1592   for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
1593     (*iter)->shutdown(level);
1594 }
1595
1596 //! Clean the composed node in case of not clean exit
1597 /*!
1598  * This method should be called on a control-c or sigterm
1599  */
1600 void ComposedNode::cleanNodes()
1601 {
1602   DEBTRACE("ComposedNode::cleanNodes");
1603   list<Node *> nodes=edGetDirectDescendants();
1604   for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
1605     (*iter)->cleanNodes();
1606 }
1607
1608 //! Reset the state of the node and its children depending on the parameter level
1609 void ComposedNode::resetState(int level)
1610 {
1611   if(level==0)return;
1612
1613   DEBTRACE("ComposedNode::resetState " << level << "," << _state);
1614   if( _state==YACS::ERROR || _state==YACS::FAILED || _state==YACS::ACTIVATED )
1615     {
1616       Node::resetState(level);
1617       std::list<Node *> nodes=edGetDirectDescendants();
1618       for(std::list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
1619         (*iter)->resetState(level);
1620     }
1621 }