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