Salome HOME
Manage initnode and finalizenode in the foreachloop progress bar.
[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 list<ElementaryNode *> ComposedNode::getRecursiveConstituents() const
1079 {
1080   list<ElementaryNode *> ret;
1081   list<Node *> setOfNode=edGetDirectDescendants();
1082   for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1083     {
1084       list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
1085       ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1086     }
1087   return ret;
1088 }
1089
1090 //! Idem getAllRecursiveNodes, but this node is NOT included.
1091 list<Node *> ComposedNode::getAllRecursiveConstituents()
1092 {
1093   list<Node *> ret;
1094   list<Node *> setOfNode=edGetDirectDescendants();
1095   for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1096     {
1097       if ( dynamic_cast<ComposedNode*> (*iter) )
1098         {
1099           list<Node *> myCurrentSet=((ComposedNode*)(*iter))->getAllRecursiveConstituents();
1100           ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1101           ret.push_back(*iter);
1102         }
1103       else
1104         {
1105           list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
1106           ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1107         }
1108     }
1109   return ret;
1110 }
1111
1112 //! Get all children nodes  elementary and composed including this node
1113 list<Node *> ComposedNode::getAllRecursiveNodes()
1114 {
1115   list<Node *> ret;
1116   list<Node *> setOfNode=edGetDirectDescendants();
1117   for(list<Node *>::iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1118     {
1119       if ( dynamic_cast<ElementaryNode*> (*iter) )
1120         {
1121           list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
1122           ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1123         }
1124       else
1125         {
1126           list<Node *> myCurrentSet=((ComposedNode*)(*iter))->getAllRecursiveNodes();
1127           ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1128         }
1129     }
1130   ret.push_back(this);
1131   return ret;
1132 }
1133
1134
1135 //! Get the progress weight for all elementary nodes
1136 /*!
1137  * Only elementary nodes have weight. A simple composed node only sum up weight of all his descendants
1138  * (working is different for loop or switch nodes)
1139  */
1140 list<ProgressWeight> ComposedNode::getProgressWeight() const
1141 {
1142   list<ProgressWeight> ret;
1143   list<Node *> setOfNode=edGetDirectDescendants();
1144   for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1145     {
1146       list<ProgressWeight> myCurrentSet=((ComposedNode*)(*iter))->getProgressWeight();
1147       ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1148     }
1149   return ret;
1150 }
1151
1152 //! Get the input port name 
1153 /*!
1154  * get the input port name used by the current node, recursively built with children names.
1155  */
1156
1157 string ComposedNode::getInPortName(const InPort * inPort) const throw(YACS::Exception)
1158 {
1159   return getPortName<InPort>(inPort);
1160 }
1161
1162 string ComposedNode::getOutPortName(const OutPort *outPort) const throw(YACS::Exception)
1163 {
1164   return getPortName<OutPort>(outPort);
1165 }
1166
1167 int ComposedNode::getNumberOfInputPorts() const
1168 {
1169   list<Node *> constituents=edGetDirectDescendants();
1170   int ret=0;
1171   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1172     ret+=(*iter)->getNumberOfInputPorts();
1173   return ret;
1174 }
1175
1176 int ComposedNode::getNumberOfOutputPorts() const
1177 {
1178   list<Node *> constituents=edGetDirectDescendants();
1179   int ret=0;
1180   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1181     ret+=(*iter)->getNumberOfOutputPorts();
1182   return ret;
1183 }
1184
1185 list<InputPort *> ComposedNode::getSetOfInputPort() const
1186 {
1187   list<Node *> constituents=edGetDirectDescendants();
1188   list<InputPort *> ret;
1189   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1190     {
1191       list<InputPort *> currentsPorts=(*iter)->getSetOfInputPort();
1192       ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1193     }
1194   return ret;
1195 }
1196
1197 list<OutputPort *> ComposedNode::getSetOfOutputPort() const
1198 {
1199   list<Node *> constituents=edGetDirectDescendants();
1200   list<OutputPort *> ret;
1201   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1202     {
1203       list<OutputPort *> currentsPorts=(*iter)->getSetOfOutputPort();
1204       ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1205     }
1206   return ret;
1207 }
1208
1209 list<InputDataStreamPort *> ComposedNode::getSetOfInputDataStreamPort() const
1210 {
1211   list<Node *> constituents=edGetDirectDescendants();
1212   list<InputDataStreamPort *> ret;
1213   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1214     {
1215       list<InputDataStreamPort *> currentsPorts=(*iter)->getSetOfInputDataStreamPort();
1216       ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1217     }
1218   return ret;
1219 }
1220
1221 list<OutputDataStreamPort *> ComposedNode::getSetOfOutputDataStreamPort() const
1222 {
1223   list<Node *> constituents=edGetDirectDescendants();
1224   list<OutputDataStreamPort *> ret;
1225   for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1226     {
1227       list<OutputDataStreamPort *> currentsPorts=(*iter)->getSetOfOutputDataStreamPort();
1228       ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1229     }
1230   return ret;
1231 }
1232
1233 OutPort *ComposedNode::getOutPort(const std::string& name) const throw(YACS::Exception)
1234 {
1235   string portName, nodeName;
1236   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false))
1237     {
1238       Node *child = getChildByShortName(nodeName);
1239       return child->getOutPort(portName);
1240     }
1241   else
1242     {
1243       string what("ComposedNode::getOutPort : the port with name "); what+=name; what+=" does not exist on the current level";
1244       throw Exception(what);
1245     }
1246 }
1247
1248 //! Get an input port given its name
1249 /*!
1250  * Contrary to YACS::ENGINE::ComposedNode::getOutputPort, this method is \b NOT recursive 
1251  * and so the leaf of type ElementaryNode aggregating
1252  * this InputPort is directly invoked.
1253  */
1254 InputPort * ComposedNode::getInputPort(const std::string& name) const throw(YACS::Exception)
1255 {
1256   try {
1257     return Node::getInputPort(name);
1258   }
1259   catch(Exception& e) {}
1260
1261   string portName, nodeName;
1262   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1263     {
1264       Node *child = getChildByName(nodeName);
1265       return child->getInputPort(portName);
1266     }
1267   else
1268     {
1269       string what("ComposedNode::getInputPort : the port with name "); what+=name; what+=" does not exist on the current level";
1270       throw Exception(what);
1271     }
1272 }
1273
1274 //! Get an output port given its name
1275 /*!
1276  * Contrary to YACS::ENGINE::ComposedNode::getInputPort, this method is recursive and go 
1277  * down hierarchy step by step to complete its work.
1278  */
1279 OutputPort * ComposedNode::getOutputPort(const std::string& name) const throw(YACS::Exception)
1280 {
1281   string portName, nodeName;
1282   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false))
1283     {
1284       Node *child = getChildByShortName(nodeName);
1285       return child->getOutputPort(portName);
1286     }
1287   else
1288     {
1289       string what("ComposedNode::getOutputPort : the port with name "); what+=name; what+=" does not exist on the current level";
1290       throw Exception(what);
1291     }
1292 }
1293
1294 InputDataStreamPort *ComposedNode::getInputDataStreamPort(const std::string& name) const throw(YACS::Exception)
1295 {
1296   string portName, nodeName;
1297   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1298     {
1299       Node *child = getChildByName(nodeName);
1300       return child->getInputDataStreamPort(portName);
1301     }
1302   else
1303     {
1304       string what("ComposedNode::getInputDataStreamPort : the port with name "); what+=name; what+=" does not exist on the current level";
1305       throw Exception(what);
1306     }
1307 }
1308
1309 OutputDataStreamPort *ComposedNode::getOutputDataStreamPort(const std::string& name) const throw(YACS::Exception)
1310 {
1311   string portName, nodeName;
1312   if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1313     {
1314       Node *child = getChildByName(nodeName);
1315       return child->getOutputDataStreamPort(portName);
1316     }
1317   else
1318     {
1319       string what("ComposedNode::getOutputDataStreamPort : the port with name "); what+=name; what+=" does not exist on the current level";
1320       throw Exception(what);
1321     }
1322 }
1323
1324 //! Update node state on receiving event from a node
1325 /*!
1326  *
1327  * \note Runtime called method. Perform, the state updating, from the son node 'node' 
1328  *       emitting the event 'event' (among Executor static const var).
1329  *         WARNING Precondition : this == node->_father
1330  * \return The event (among Executor static const var) destinated to this->_father node 
1331  *         to perform eventually up level update.
1332  *
1333  * Calls ComposedNode::updateStateOnStartEventFrom if event is YACS::START
1334  *
1335  * Calls ComposedNode::updateStateOnFinishedEventFrom if event is YACS::FINISH
1336  *
1337  * Called by ComposedNode::notifyFrom
1338  */
1339 YACS::Event ComposedNode::updateStateFrom(Node *node,        //* I : node emitting event
1340                                           YACS::Event event,  //* I : event emitted
1341                                           const Executor *execInst
1342                                           )
1343 {
1344   DEBTRACE("updateStateFrom: " << node->getName() << " " << event);
1345   try
1346     {
1347       switch(event)
1348         {
1349         case YACS::START:
1350           return updateStateOnStartEventFrom(node);
1351           break;
1352         case YACS::FINISH:
1353           return updateStateOnFinishedEventFrom(node);
1354           break;
1355         case YACS::ABORT:
1356           return updateStateOnFailedEventFrom(node,execInst);
1357           break;
1358         default:
1359           return YACS::NOEVENT;//TODO unexpected type of event
1360           break;
1361         }
1362     }
1363   catch(YACS::Exception& ex)
1364     {
1365       //unexpected exception: probably a bug in engine
1366       //try to keep a consistent global state
1367       DEBTRACE( "updateStateFrom: " << ex.what() );
1368       _errorDetails="Internal error: ";
1369       _errorDetails=_errorDetails + ex.what();
1370       setState(YACS::ERROR);
1371       exForwardFailed();
1372       return YACS::ABORT;
1373     }
1374   catch(...)
1375     {
1376       //unexpected exception: probably a bug in engine
1377       //try to keep a consistent global state
1378       setState(YACS::ERROR);
1379       exForwardFailed();
1380       return YACS::ABORT;
1381     }
1382 }
1383
1384 //! Method used to notify the node that a child node has started
1385 /*!
1386  * Update the ComposedNode state and return the ComposedNode change state 
1387  *
1388  *  \param node : the child node that has started
1389  *  \return the loop state change
1390  */
1391 YACS::Event ComposedNode::updateStateOnStartEventFrom(Node *node)
1392 {
1393   setState(YACS::ACTIVATED);
1394   return YACS::START;
1395 }
1396
1397 //! Method used to notify the node that a child node has failed
1398 YACS::Event ComposedNode::updateStateOnFailedEventFrom(Node *node, const Executor *execInst)
1399 {
1400    setState(YACS::FAILED);
1401    return YACS::ABORT;
1402 }
1403
1404 void ComposedNode::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
1405                                         InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(YACS::Exception)
1406 {
1407   if((dynamic_cast<DataFlowPort *>(start) || dynamic_cast<DataFlowPort *>(end))
1408      && (dynamic_cast<DataStreamPort *>(start) || dynamic_cast<DataStreamPort *>(end)))
1409     {//cross protocol required : deeper check needed
1410       bool isOK=false;
1411       list<ComposedNode *>::const_iterator iter;
1412       for(iter=pointsOfViewStart.begin();iter!=pointsOfViewStart.end() && !isOK;iter++)
1413         isOK=(*iter)->isRepeatedUnpredictablySeveralTimes();
1414       for(iter=pointsOfViewEnd.begin();iter!=pointsOfViewEnd.end() && !isOK;iter++)
1415         isOK=(*iter)->isRepeatedUnpredictablySeveralTimes();
1416       if(!isOK)
1417         throw Exception("ComposedNode::checkLinkPossibility : Request for cross protocol link impossible.");
1418     }
1419 }
1420
1421 void ComposedNode::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
1422 {
1423 }
1424
1425 void ComposedNode::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
1426 {
1427 }
1428
1429 void ComposedNode::getDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
1430 {
1431 }
1432
1433 void ComposedNode::getDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
1434 {
1435 }
1436
1437 void ComposedNode::releaseDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
1438 {
1439 }
1440
1441 void ComposedNode::releaseDelegateOf(OutPort *portDwn, OutPort *portUp, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
1442 {
1443 }
1444
1445 void ComposedNode::loaded()
1446 {
1447 }
1448 void ComposedNode::connected()
1449 {
1450 }
1451
1452 void ComposedNode::accept(Visitor *visitor)
1453 {
1454   list<Node *> constituents=edGetDirectDescendants();
1455   for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1456     {
1457       (*iter)->accept(visitor);
1458     }
1459 }
1460
1461 //! redefined on derived class of ComposedNode. by default a ComposedNode has no port by itself
1462 std::list<InputPort *> ComposedNode::getLocalInputPorts() const
1463 {
1464   std::list<InputPort *> lip; return lip; // empty list
1465 }
1466
1467 //! redefined on derived class of ComposedNode. by default a ComposedNode has no port by itself
1468 std::list<OutputPort *> ComposedNode::getLocalOutputPorts() const
1469 {
1470   std::list<OutputPort *> lop; return lop; // empty list
1471 }
1472
1473 bool ComposedNode::isNameAlreadyUsed(const std::string& name) const
1474 {
1475   return false;
1476 }
1477
1478 void ComposedNode::edUpdateState()
1479 {
1480   DEBTRACE("ComposedNode::edUpdateState(): " << _state << " " << _modified);
1481   YACS::StatesForNode state=YACS::READY;
1482
1483   try
1484     {
1485       checkBasicConsistency();
1486       _errorDetails="";
1487     }
1488   catch(Exception& e)
1489     {
1490       state=YACS::INVALID;
1491       _errorDetails=e.what();
1492     }
1493   DEBTRACE("ComposedNode::edUpdateState: " << _errorDetails);
1494
1495   //update children if needed
1496   list<Node *> constituents=edGetDirectDescendants();
1497   for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1498     {
1499       if(!(*iter)->isValid())
1500         state=YACS::INVALID;
1501     }
1502   if(state != _state)
1503     setState(state);
1504   _modified=0;
1505 }
1506
1507 std::string ComposedNode::getErrorReport()
1508 {
1509   DEBTRACE("ComposedNode::getErrorReport: " << getName() << " " << _state);
1510   YACS::StatesForNode effectiveState=getEffectiveState();
1511
1512   if(effectiveState != YACS::INVALID &&  effectiveState != YACS::ERROR && effectiveState != YACS::FAILED)
1513     return "";
1514
1515   std::string report="<error node= " + getName();
1516   switch(effectiveState)
1517     {
1518     case YACS::INVALID:
1519       report=report+" state= INVALID";
1520       break;
1521     case YACS::ERROR:
1522       report=report+" state= ERROR";
1523       break;
1524     case YACS::FAILED:
1525       report=report+" state= FAILED";
1526       break;
1527     default:
1528       break;
1529     }
1530   report=report + ">\n" ;
1531   if(_errorDetails != "")
1532     report=report+_errorDetails+"\n";
1533
1534   list<Node *> constituents=edGetDirectDescendants();
1535   for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1536     {
1537       std::string rep=(*iter)->getErrorReport();
1538       if(rep != "")
1539         {
1540           report=report+rep+"\n";
1541         }
1542     }
1543   report=report+"</error>";
1544   return report;
1545 }
1546
1547
1548
1549 void ComposedNode::checkBasicConsistency() const throw(YACS::Exception)
1550 {
1551   DEBTRACE("ComposedNode::checkBasicConsistency");
1552   std::list<InputPort *>::const_iterator iter;
1553   std::list<InputPort *> inports=getLocalInputPorts();
1554   for(iter=inports.begin();iter!=inports.end();iter++)
1555     (*iter)->checkBasicConsistency();
1556 }
1557
1558 //! Stop all pending activities of the composed node
1559 /*!
1560  * This method should be called when a Proc is finished and must be deleted from the YACS server
1561  */
1562 void ComposedNode::shutdown(int level)
1563 {
1564   if(level==0)return;
1565   DEBTRACE("ComposedNode::shutdown");
1566   list<Node *> nodes=edGetDirectDescendants();
1567   for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
1568     (*iter)->shutdown(level);
1569 }
1570
1571 //! Clean the composed node in case of not clean exit
1572 /*!
1573  * This method should be called on a control-c or sigterm
1574  */
1575 void ComposedNode::cleanNodes()
1576 {
1577   DEBTRACE("ComposedNode::cleanNodes");
1578   list<Node *> nodes=edGetDirectDescendants();
1579   for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
1580     (*iter)->cleanNodes();
1581 }
1582
1583 //! Reset the state of the node and its children depending on the parameter level
1584 void ComposedNode::resetState(int level)
1585 {
1586   if(level==0)return;
1587
1588   DEBTRACE("ComposedNode::resetState " << level << "," << _state);
1589   if( _state==YACS::ERROR || _state==YACS::FAILED || _state==YACS::ACTIVATED )
1590     {
1591       Node::resetState(level);
1592       std::list<Node *> nodes=edGetDirectDescendants();
1593       for(std::list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
1594         (*iter)->resetState(level);
1595     }
1596 }