Salome HOME
Synchronize adm files
[modules/yacs.git] / src / engine / DynParaLoop.cxx
1 // Copyright (C) 2006-2014  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 "DynParaLoop.hxx"
21 #include "LinkInfo.hxx"
22 #include "OutPort.hxx"
23 #include "Container.hxx"
24 #include "ComponentInstance.hxx"
25 #include "ServiceNode.hxx"
26 #include "InlineNode.hxx"
27 #include "ElementaryNode.hxx"
28 #include "Visitor.hxx"
29
30 #include <list>
31 #include <vector>
32
33 //#define _DEVDEBUG_
34 #include "YacsTrace.hxx"
35
36 using namespace std;
37 using namespace YACS::ENGINE;
38
39 const char DynParaLoop::NAME_OF_SPLITTED_SEQ_OUT[] = "evalSamples";
40 const char DynParaLoop::OLD_NAME_OF_SPLITTED_SEQ_OUT[] = "SmplPrt"; // For backward compatibility with 5.1.4
41
42 const char DynParaLoop::NAME_OF_NUMBER_OF_BRANCHES[]="nbBranches";
43
44 DynParaLoop::DynParaLoop(const std::string& name, TypeCode *typeOfDataSplitted)
45   : ComposedNode(name),_node(0),_initNode(0),_finalizeNode(0),_nbOfEltConsumed(0),
46     _nbOfBranches(NAME_OF_NUMBER_OF_BRANCHES,this,Runtime::_tc_int),
47     _splittedPort(NAME_OF_SPLITTED_SEQ_OUT,this,typeOfDataSplitted)
48 {
49 }
50
51 DynParaLoop::~DynParaLoop()
52 {
53   delete _node;
54   delete _initNode;
55   delete _finalizeNode;
56 }
57
58 DynParaLoop::DynParaLoop(const DynParaLoop& other, ComposedNode *father, bool editionOnly)
59   : ComposedNode(other,father), _nbOfBranches(other._nbOfBranches,this),
60     _splittedPort(other._splittedPort,this), _node(0), _initNode(0), _finalizeNode(0),
61     _nbOfEltConsumed(0)
62 {
63   if(other._node)
64     _node=other._node->clone(this,editionOnly);
65   if(other._initNode)
66     _initNode=other._initNode->clone(this,editionOnly);
67   if(other._finalizeNode)
68     _finalizeNode = other._finalizeNode->clone(this,editionOnly);
69   const AnyOutputPort& startOfLinksToReproduce=other._splittedPort;
70   set<InPort *> endsOfLinksToReproduce=startOfLinksToReproduce.edSetInPort();
71   for(set<InPort *>::iterator iter=endsOfLinksToReproduce.begin();iter!=endsOfLinksToReproduce.end();iter++)
72     edAddLink(&_splittedPort,getInPort(other.getPortName(*iter)));
73 }
74
75 Node *DynParaLoop::edSetNode(Node *node)
76 {
77   return checkConsistencyAndSetNode(_node, node);
78 }
79
80 //! This method is used to factorize methods edSetNode, edSetInitNode and edSetFinalizeNode
81 Node * DynParaLoop::checkConsistencyAndSetNode(Node* &nodeToReplace, Node* node)
82 {
83   if (node == NULL || nodeToReplace == node)
84     return 0;
85   if (node->_father)
86     throw Exception(string("Can't set node: node ") + node->getName() + " is not orphan.");
87   if (_node && _node != nodeToReplace && _node->getName() == node->getName())
88     throw Exception(string("Can't set node: node ") + node->getName() +
89                     " has the same name than exec node already in " + _name + ".");
90   if (_initNode && _initNode != nodeToReplace && _initNode->getName() == node->getName())
91     throw Exception(string("Can't set node: node ") + node->getName() +
92                     " has the same name than init node already in " + _name + ".");
93   if (_finalizeNode && _finalizeNode != nodeToReplace && _finalizeNode->getName() == node->getName())
94     throw Exception(string("Can't set node: node ") + node->getName() +
95                     " has the same name than finalize node already in " + _name + ".");
96   checkNoCrossHierachyWith(node);
97   ComposedNode::edRemoveChild(nodeToReplace);
98   Node * ret = nodeToReplace;
99   nodeToReplace = node;
100   nodeToReplace->_father = this;
101   // set _modified flag so that edUpdateState can refresh state
102   modified();
103   return ret;
104 }
105
106 void DynParaLoop::init(bool start)
107 {
108   ComposedNode::init(start);
109   if(!_node)
110     {
111       string what("DynParaLoop::init : no node specified for ForEachLoop with name "); what +=_name;
112       throw Exception(what);
113     }
114   _node->init(start);
115   if (_initNode) _initNode->init(start);
116   if (_finalizeNode) _finalizeNode->init(start);
117   _nbOfBranches.exInit(start);
118   _splittedPort.exInit();
119   _nbOfEltConsumed=0;
120 }
121
122 Node *DynParaLoop::edSetInitNode(Node *node)
123 {
124   return checkConsistencyAndSetNode(_initNode, node);
125 }
126
127 Node * DynParaLoop::edSetFinalizeNode(Node * node)
128 {
129   return checkConsistencyAndSetNode(_finalizeNode, node);
130 }
131
132 //! Connect an OutPort to an InPort and add control link if necessary
133 /*!
134  * Connect the ports with a data link (edAddLink)
135  * In a Loop don't add control flow link : use this only to add data back links
136  *
137  * \param start : the OutPort to connect
138  * \param end : the InPort to connect
139  * \return  true if a new link has been created, false otherwise.
140  */
141 bool DynParaLoop::edAddDFLink(OutPort *start, InPort *end) throw(YACS::Exception)
142 {
143   return edAddLink(start,end);
144 }
145
146 int DynParaLoop::getNumberOfInputPorts() const
147 {
148   return ComposedNode::getNumberOfInputPorts()+1;
149 }
150
151 int DynParaLoop::getNumberOfOutputPorts() const
152 {
153   return ComposedNode::getNumberOfOutputPorts()+1;
154 }
155
156 std::list<OutputPort *> DynParaLoop::getSetOfOutputPort() const
157 {
158   list<OutputPort *> ret=ComposedNode::getSetOfOutputPort();
159   ret.push_back((OutputPort *)&_splittedPort);
160   return ret;
161 }
162
163 std::list<OutputPort *> DynParaLoop::getLocalOutputPorts() const
164 {
165   list<OutputPort *> ret=ComposedNode::getLocalOutputPorts();
166   ret.push_back((OutputPort *)&_splittedPort);
167   return ret;
168 }
169
170 OutPort *DynParaLoop::getOutPort(const std::string& name) const throw(YACS::Exception)
171 {
172   if (name == NAME_OF_SPLITTED_SEQ_OUT || name == OLD_NAME_OF_SPLITTED_SEQ_OUT)
173     return (OutPort *)&_splittedPort;
174   return ComposedNode::getOutPort(name);
175 }
176
177
178 OutputPort *DynParaLoop::getOutputPort(const std::string& name) const throw(YACS::Exception)
179 {
180   if (name == NAME_OF_SPLITTED_SEQ_OUT || name == OLD_NAME_OF_SPLITTED_SEQ_OUT)
181     return (OutputPort *)&_splittedPort;
182   return ComposedNode::getOutputPort(name);
183 }
184
185 bool DynParaLoop::isPlacementPredictableB4Run() const
186 {
187   return false;
188 }
189
190 Node *DynParaLoop::edRemoveNode()
191 {
192   return removeNode(_node);
193 }
194
195 //! This method is used to factorize methods edRemoveNode, edRemoveInitNode and edRemoveFinalizeNode
196 Node * DynParaLoop::removeNode(Node* &nodeToRemove)
197 {
198   if (!nodeToRemove)
199     return NULL;
200   ComposedNode::edRemoveChild(nodeToRemove);
201   Node * ret = nodeToRemove;
202   nodeToRemove = NULL;
203   modified();
204   return ret;
205 }
206
207 Node *DynParaLoop::edRemoveInitNode()
208 {
209   return removeNode(_initNode);
210 }
211
212 Node * DynParaLoop::edRemoveFinalizeNode()
213 {
214   return removeNode(_finalizeNode);
215 }
216
217 void DynParaLoop::edRemoveChild(Node *node) throw(YACS::Exception)
218 {
219   ComposedNode::edRemoveChild(node);
220   if(node==_node)
221     _node=0;
222   if(node==_initNode)
223     _initNode=0;
224   if(node==_finalizeNode)
225     _finalizeNode=0;
226   modified();
227 }
228
229 bool DynParaLoop::edAddChild(Node *DISOWNnode) throw(YACS::Exception)
230 {
231   return edSetNode(DISOWNnode);
232 }
233
234 std::list<Node *> DynParaLoop::edGetDirectDescendants() const
235 {
236   list<Node *> ret;
237   if(_node)
238     ret.push_back(_node);
239   if(_initNode)
240     ret.push_back(_initNode);
241   if(_finalizeNode)
242     ret.push_back(_finalizeNode);
243   return ret;
244 }
245
246 std::list<InputPort *> DynParaLoop::getSetOfInputPort() const
247 {
248   list<InputPort *> ret=ComposedNode::getSetOfInputPort();
249   ret.push_back((InputPort *)&_nbOfBranches);
250   return ret;
251 }
252
253 InputPort *DynParaLoop::getInputPort(const std::string& name) const throw(YACS::Exception)
254 {
255   if(name==NAME_OF_NUMBER_OF_BRANCHES)
256     return (InputPort *)&_nbOfBranches;
257   return ComposedNode::getInputPort(name);
258 }
259
260 std::list<InputPort *> DynParaLoop::getLocalInputPorts() const
261 {
262   list<InputPort *> ret=ComposedNode::getLocalInputPorts();
263   ret.push_back((InputPort *)&_nbOfBranches);
264   return ret;
265 }
266
267 unsigned DynParaLoop::getNumberOfBranchesCreatedDyn() const throw(YACS::Exception)
268 {
269   if(_execNodes.empty())
270     throw Exception("ForEachLoop::getNumberOfBranches : No branches created dynamically ! - ForEachLoop needs to run or to be runned to call getNumberOfBranches");
271   else
272     return _execNodes.size();
273 }
274
275 Node *DynParaLoop::getChildByShortName(const std::string& name) const throw(YACS::Exception)
276 {
277   if (_node && name == _node->getName())
278     return _node;
279   if (_initNode && name == _initNode->getName())
280     return  _initNode;
281   if (_finalizeNode && name == _finalizeNode->getName())
282     return  _finalizeNode;
283   std::string what("node "); what+= name ; what+=" is not a child of DynParaLoop node "; what += getName();
284   throw Exception(what);
285 }
286
287 Node *DynParaLoop::getChildByNameExec(const std::string& name, unsigned id) const throw(YACS::Exception)
288 {
289   if(id>=getNumberOfBranchesCreatedDyn())
290     throw Exception("ForEachLoop::getChildByNameExec : invalid id - too large compared with dynamically created branches.");
291   if (_node && name == _node->getName())
292     return _execNodes[id];
293   if (_initNode && name == _initNode->getName())
294     return _execInitNodes[id];
295   if (_finalizeNode && name == _finalizeNode->getName())
296     return _execFinalizeNodes[id];
297   std::string what("node "); what+= name ; what+=" is not a child of DynParaLoop node "; what += getName();
298   throw Exception(what);
299 }
300
301 void DynParaLoop::cleanDynGraph()
302 {
303   vector<Node *>::iterator iter;
304   for(iter=_execNodes.begin() ; iter!=_execNodes.end() ; iter++)
305     delete *iter;
306   _execNodes.clear();
307   for(iter=_execInitNodes.begin() ; iter!=_execInitNodes.end() ; iter++)
308     delete *iter;
309   _execInitNodes.clear();
310   for(iter=_execFinalizeNodes.begin() ; iter!=_execFinalizeNodes.end() ; iter++)
311     delete *iter;
312   _execFinalizeNodes.clear();
313 }
314
315 /*!
316  * This method applies on newly cloned on exec nodes (_execNodes/_execInitNodes)
317  * the setting of input ports coming from outside of 'this'
318  */
319 void DynParaLoop::prepareInputsFromOutOfScope(int branchNb)
320 {
321   set< InPort * > portsToSetVals=getAllInPortsComingFromOutsideOfCurrentScope();
322
323   // This tweak is to fix problems with nested dynamic loops where links are not cloned properly
324   list<InPort *> temp = getSetOfInPort();
325   for(list<InPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
326     {
327       if ((*iter2)->edSetOutPort().size() == 1 && *(*iter2)->edSetOutPort().begin() == NULL)
328         {
329           portsToSetVals.insert(*iter2);
330         }
331     }
332
333   // local input ports are not candidates for dynamically duplicated inport.
334   list<InputPort *> localPorts = getLocalInputPorts();
335   for(list<InputPort *>::iterator iter = localPorts.begin() ; iter != localPorts.end() ; iter++)
336     portsToSetVals.erase(*iter);
337   for(set< InPort * >::iterator iter=portsToSetVals.begin();iter!=portsToSetVals.end();iter++)
338     {
339       InputPort *curPortCasted=(InputPort *) *iter;//Cast granted by ForEachLoop::buildDelegateOf(InPort)
340       void *val=curPortCasted->get();
341       InputPort *portToSet=getDynInputPortByAbsName(branchNb,getInPortName(*iter),true);
342       if(portToSet)//portToSet==0 in case of portToSet==_splitterNode._dataPortToDispatch of ForEach
343         {
344           portToSet->put((const void *)val);
345           portToSet->edNotifyReferencedBy(0);//This is to indicate that somewhere somebody deals with this inputport
346           //even if no direct physical link exists. This exclusively for _execNodes[branchNb]::init on the next turn of loop.
347         }
348     }
349 }
350
351 void DynParaLoop::putValueOnBranch(Any *val, unsigned branchId, bool first)
352 {
353   bool isDispatched = false;
354   set<InPort *> inPrtLkdWthSplttdPrt=_splittedPort.edSetInPort();
355   for(set<InPort *>::iterator iter=inPrtLkdWthSplttdPrt.begin();iter!=inPrtLkdWthSplttdPrt.end();iter++)
356     {
357       std::string portNameOnCurPrt=getPortName(*iter);
358       InputPort *portOnGivenBranch=getDynInputPortByAbsName(branchId,portNameOnCurPrt,first);//Cast granted because impossible to have cross protocol with _splittedPort
359       //see OptimizerLoop::buildDelegateOf
360       if(portOnGivenBranch)
361         {
362           if(first)
363             portOnGivenBranch->edNotifyReferencedBy(0);
364           InputPort *traducer=getRuntime()->adapt(portOnGivenBranch,
365                                                   Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME,_splittedPort.edGetType());
366           traducer->put((const void *)val);
367           isDispatched = true;
368           if(traducer!=portOnGivenBranch)
369             delete traducer;
370         }
371     }
372   if ( isDispatched )
373     {
374       Any *tmp=val->clone();
375       _splittedPort.setValue(tmp);
376       tmp->decrRef();
377     }
378 }
379
380 DynParaLoop::TypeOfNode DynParaLoop::getIdentityOfNotifyerNode(const Node *node, unsigned& id)
381 {
382   vector<Node *>::iterator iter;
383   id=0;
384   for (iter=_execNodes.begin() ; iter!=_execNodes.end() ; iter++,id++)
385     if (*iter==node)
386       return WORK_NODE;
387   id=0;
388   for (iter=_execInitNodes.begin() ; iter!=_execInitNodes.end() ; iter++,id++)
389     if (*iter==node)
390       return INIT_NODE;
391   id=0;
392   for (iter=_execFinalizeNodes.begin() ; iter!=_execFinalizeNodes.end() ; iter++,id++)
393     if (*iter==node)
394       return FINALIZE_NODE;
395 }
396
397 bool DynParaLoop::isMultiplicitySpecified(unsigned& value) const
398 {
399   if(_nbOfBranches.edIsManuallyInitialized())
400     if(_nbOfBranches.edGetNumberOfLinks()==0)
401       {
402         value=_nbOfBranches.getIntValue();
403         return true;
404       }
405   return false;
406 }
407
408 void DynParaLoop::forceMultiplicity(unsigned value)
409 {
410   _nbOfBranches.edRemoveAllLinksLinkedWithMe();
411   _nbOfBranches.edInit((int)value);
412 }
413
414 void DynParaLoop::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
415 {
416   string typeOfPortInstance=port->getNameOfTypeOfCurrentInstance();
417   if(typeOfPortInstance!=InputPort::NAME)
418     throw Exception("DynParaLoop::buildDelegateOf : A link with datastream end inside DynParaLoop this is not possible");
419 }
420
421 void DynParaLoop::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
422 {
423   if(_initNode)
424     if(isInMyDescendance(port.first->getNode())==_initNode)
425       throw Exception("DynParaLoop::buildDelegateOf : uncorrect ForEach link : a link starting from init node can't leave the scope of ForEachLoop node it belongs to.");
426   if(port.first==&_splittedPort)
427     throw Exception("DynParaLoop::buildDelegateOf : uncorrect ForEach link : splitted port must be link within the scope of ForEachLoop node it belongs to.");
428 }
429
430 void DynParaLoop::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
431 {
432   const char what[]="DynParaLoop::checkCFLinks : internal error.";
433   //First dealing checkCFLinks forwarding...
434   if(isInMyDescendance(end->getNode())==0)//no chance that _splittedPort is in starts due to buildDelegate.
435     solveObviousOrDelegateCFLinks(starts,end,alreadyFed,direction,info);
436   else
437     {//no forwarding here.
438       if(starts.size()!=1)
439         throw Exception(what);
440       //ASSERT(direction) : see DynParaLoop::checkControlDependancy only 'fw' filled.
441       if(*(starts.begin())!=&_splittedPort)
442         throw Exception(what);
443       if(alreadyFed==FREE_ST)
444         alreadyFed=FED_ST;
445       else if(alreadyFed==FED_ST)
446         {//Shame ! splittedPort fills a port already fed...
447           info.pushInfoLink(*(starts.begin()),end,I_USELESS);
448         }
449     }
450 }
451
452 /*!
453  * \param start : start port
454  * \param end : end port
455  * \param cross indicates if start -> end link is a DS link behind.
456  * \param fw out parameter.
457  * \param fwCross out parameter storing links where a cross has been detected.
458  * \param bw out parameter where backward links are stored.
459  * \param info : collected information
460  */
461 void DynParaLoop::checkControlDependancy(OutPort *start, InPort *end, bool cross,
462                                          std::map < ComposedNode *,  std::list < OutPort * >, SortHierarc >& fw,
463                                          std::vector<OutPort *>& fwCross,
464                                          std::map< ComposedNode *, std::list < OutPort *>, SortHierarc >& bw,
465                                          LinkInfo& info) const
466 {
467   if(start==&_splittedPort)
468     fw[(ComposedNode *)this].push_back(start);
469   else
470     throw Exception("DynParaLoop::checkControlDependancy : Internal error occured - should never been called !");
471 }
472
473 /*!
474  * \note : For a given name 'name' of port in absolute form from this, returns the corresponding InputPort 
475  *         instance of the port for the branch # 'branchNb'. 
476  *         The port can be part of _node or _initNode if it exists (if 'initNodeAdmitted' is true).
477  *         \b WARNING : no check performed on  'branchNb' value to see if it is compatible with size of '_execNodes'.
478  *         This method is called to dispatch value on each InputPort linked to this->._splitterNode._splittedPort
479  */
480 InputPort *DynParaLoop::getDynInputPortByAbsName(int branchNb, const std::string& name, bool initNodeAdmitted)
481 {
482   string portName, nodeName;
483   splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true);
484   Node *staticChild = getChildByName(nodeName);
485   Node *desc=isInMyDescendance(staticChild);
486   if(desc==_node)
487     {
488       splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false);
489       return _execNodes[branchNb]->getInputPort(portName);
490     }
491   else if(desc==_initNode)
492     if(initNodeAdmitted)
493       {
494         splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false);
495         return _execInitNodes[branchNb]->getInputPort(portName);
496       }
497   return 0;
498 }
499
500 void DynParaLoop::checkBasicConsistency() const throw(YACS::Exception)
501 {
502   DEBTRACE("DynParaLoop::checkBasicConsistency");
503   ComposedNode::checkBasicConsistency();
504   if(!_node)
505     throw Exception("For a dynamic loop, internal node is mandatory");
506 }
507
508 std::string DynParaLoop::getErrorReport()
509 {
510   DEBTRACE("DynParaLoop::getErrorReport: " << getName() << " " << _state);
511   YACS::StatesForNode effectiveState=getEffectiveState();
512
513   if(effectiveState != YACS::INVALID &&  effectiveState != YACS::ERROR && effectiveState != YACS::FAILED)
514     return "";
515
516   std::string report="<error node= " + getName();
517   switch(effectiveState)
518     {
519     case YACS::INVALID:
520       report=report+" state= INVALID";
521       break;
522     case YACS::ERROR:
523       report=report+" state= ERROR";
524       break;
525     case YACS::FAILED:
526       report=report+" state= FAILED";
527       break;
528     default:
529       break;
530     }
531   report=report + ">\n" ;
532   if(_errorDetails != "")
533     report=report+_errorDetails+"\n";
534
535   if(_execNodes.empty())
536     {
537       // edition node
538       list<Node *> constituents=edGetDirectDescendants();
539       for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
540         {
541           std::string rep=(*iter)->getErrorReport();
542           if(rep != "")
543             {
544               report=report+rep+"\n";
545             }
546         }
547     }
548   else
549     {
550       // execution nodes
551       for(vector<Node *>::iterator iter=_execInitNodes.begin();iter!=_execInitNodes.end();iter++)
552         {
553           std::string rep=(*iter)->getErrorReport();
554           if(rep != "")
555             {
556               report=report+rep+"\n";
557             }
558         }
559       for(vector<Node *>::iterator iter=_execNodes.begin();iter!=_execNodes.end();iter++)
560         {
561           std::string rep=(*iter)->getErrorReport();
562           if(rep != "")
563             {
564               report=report+rep+"\n";
565             }
566         }
567       for(vector<Node *>::iterator iter=_execFinalizeNodes.begin();iter!=_execFinalizeNodes.end();iter++)
568         {
569           std::string rep=(*iter)->getErrorReport();
570           if(rep != "")
571             {
572               report=report+rep+"\n";
573             }
574         }
575     }
576
577   report=report+"</error>";
578   return report;
579 }
580
581 void DynParaLoop::forwardExecStateToOriginalBody(Node *execNode)
582 {
583   unsigned int id;
584   Node * origNode = NULL;
585   switch (getIdentityOfNotifyerNode(execNode,id))
586     {
587     case INIT_NODE:
588     {
589       origNode = _initNode;
590       break;
591     }
592     case WORK_NODE:
593     {
594       origNode = _node;
595       break;
596     }
597     case FINALIZE_NODE:
598     {
599       origNode = _finalizeNode;
600       break;
601     }
602     default:
603       YASSERT(false)
604     }
605
606   YASSERT(origNode != NULL)
607   origNode->setState(execNode->getState());
608   origNode->setErrorDetails(execNode->getErrorDetails());
609
610   ComposedNode* compNode = dynamic_cast<ComposedNode*>(origNode);
611   ComposedNode* compNodeExe = dynamic_cast<ComposedNode*>(execNode);
612   if (compNode && compNodeExe)
613     {
614       list<Node *> aChldn = compNodeExe->getAllRecursiveConstituents();
615       list<Node *>::iterator iter=aChldn.begin();
616       for(;iter!=aChldn.end();iter++)
617         {
618           Node* node=compNode->getChildByName(compNodeExe->getChildName(*iter));
619           node->setState((*iter)->getState());
620           node->setErrorDetails((*iter)->getErrorDetails());
621         }
622     }
623 }
624
625 //! Method used to notify the node that a child node has failed
626 /*!
627  * Update the current state and return the change state
628  *
629  *  \param node : the child node that has failed
630  *  \return the state change
631  */
632 YACS::Event DynParaLoop::updateStateOnFailedEventFrom(Node *node)
633 {
634   DEBTRACE("DynParaLoop::updateStateOnFailedEventFrom " << node->getName());
635   setState(YACS::FAILED);
636   forwardExecStateToOriginalBody(node);
637   unsigned int id;
638   switch (getIdentityOfNotifyerNode(node,id))
639     {
640     case INIT_NODE:
641     {
642       _node->setState(YACS::FAILED);
643       if (_finalizeNode != NULL) _finalizeNode->setState(YACS::FAILED);
644       break;
645     }
646     case WORK_NODE:
647     {
648       if (_finalizeNode != NULL) _finalizeNode->setState(YACS::FAILED);
649       break;
650     }
651     }
652   return YACS::ABORT;
653 }
654
655 //! Clone nodes and make their placement consistent with the placement of the original ones.
656 /*!
657  *  For instance, if two original nodes are placed on a component comp1 in a container cont1
658  *  and a third one is placed on a component comp2 in the container cont1, the clones of the two
659  *  first nodes will be placed on a component comp3 in a container cont2 and the third clone
660  *  will be placed on a component comp4 in the container cont2.
661  */
662 vector<Node *> DynParaLoop::cloneAndPlaceNodesCoherently(const vector<Node *> & origNodes)
663 {
664   DEBTRACE("Begin cloneAndPlaceNodesCoherently")
665   vector<Node *> clones;
666   DeploymentTree treeToDup;
667   vector<list<ElementaryNode *> > origElemNodeList;
668   for (int i=0 ; i<origNodes.size() ; i++)
669     {
670       DEBTRACE("Cloning node " << i)
671       if (origNodes[i] == NULL)
672         {
673           DEBTRACE("Cloning node " << i << ", NULL" )
674           clones.push_back(NULL);
675           origElemNodeList.push_back(list<ElementaryNode *>());
676         }
677       else
678         {
679           DEBTRACE("Cloning node " << i << "," << origNodes[i]->getName())
680           clones.push_back(origNodes[i]->simpleClone(this, false));
681           list<ElementaryNode *> tasks = origNodes[i]->getRecursiveConstituents();
682           origElemNodeList.push_back(tasks);
683           for (list< ElementaryNode *>::iterator iter=tasks.begin() ; iter!=tasks.end() ; iter++)
684             treeToDup.appendTask(*iter, (*iter)->getDynClonerIfExists(this));
685         }
686     }
687
688   DEBTRACE("Placing nodes...")
689   vector<Container *> conts=treeToDup.getAllContainers();
690
691   //iterate on all containers
692   for(vector<Container *>::iterator iterCt=conts.begin();iterCt!=conts.end();iterCt++)
693     {
694       DEBTRACE("Container " << ((*iterCt)?(*iterCt)->getName():"NULL"))
695       vector<ComponentInstance *> comps=treeToDup.getComponentsLinkedToContainer(*iterCt);
696       Container *contCloned=0;
697       if((*iterCt))
698         contCloned=(*iterCt)->clone();
699
700       //iterate on all component instances linked to the container
701       for(vector<ComponentInstance *>::iterator iterCp=comps.begin();iterCp!=comps.end();iterCp++)
702         {
703           DEBTRACE("Component " << (*iterCp)->getCompoName())
704           vector<Task *> tasks=treeToDup.getTasksLinkedToComponent(*iterCp);
705           ComponentInstance *curCloned=(*iterCp)->clone();
706           DEBTRACE("Assign container " << (*iterCp)->getCompoName())
707           curCloned->setContainer(contCloned);
708           for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
709             {
710               DEBTRACE("Task " << ((ElementaryNode *)(*iterT))->getName())
711               int i = 0;
712               ElementaryNode * origElemNode = NULL;
713               for (i=0 ; i<origNodes.size() ; i++)
714                 if (origNodes[i] != NULL)
715                   {
716                     DEBTRACE("Looking in original node " << i)
717                     list<ElementaryNode *>::iterator res=find(origElemNodeList[i].begin(),
718                                                               origElemNodeList[i].end(),
719                                                               (ElementaryNode *)(*iterT));
720                     if (res != origElemNodeList[i].end()) {
721                       origElemNode = *res;
722                       break;
723                     }
724                   }
725
726               YASSERT(origElemNode != NULL)
727               DEBTRACE("Found task in node " << i)
728               ServiceNode * nodeC = NULL;
729               if (origNodes[i] == origElemNode)
730                 nodeC = (ServiceNode *)clones[i];
731               else
732                 {
733                   string childName = ((ComposedNode *)origNodes[i])->getChildName(origElemNode);
734                   nodeC = (ServiceNode *)clones[i]->getChildByName(childName);
735                 }
736               DEBTRACE("Assign component: " << (*iterCp)->getCompoName() << "," << nodeC->getName())
737               nodeC->setComponent(curCloned);
738             }
739           curCloned->decrRef();
740         }
741
742       // iterate on all tasks linked to the container
743       vector<Task *> tasks=treeToDup.getTasksLinkedToContainer(*iterCt);
744       for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
745         {
746           DEBTRACE("Task " << ((ElementaryNode *)(*iterT))->getName())
747           int i = 0;
748           ElementaryNode * origElemNode = NULL;
749           for (i=0 ; i<origNodes.size() ; i++)
750             if (origNodes[i] != NULL)
751               {
752                 DEBTRACE("Looking in original node " << i)
753                 list<ElementaryNode *>::iterator res=find(origElemNodeList[i].begin(),
754                                                           origElemNodeList[i].end(),
755                                                           (ElementaryNode *)(*iterT));
756                 if (res != origElemNodeList[i].end()) 
757                   {
758                     origElemNode = *res;
759                     break;
760                   }
761               }
762           YASSERT(origElemNode != NULL)
763           DEBTRACE("Found task in node " << i)
764           InlineFuncNode * nodeC = NULL;
765           if (origNodes[i] == origElemNode)
766             {
767               nodeC = (InlineFuncNode *)clones[i];
768             }
769           else
770             {
771               string childName = ((ComposedNode *)origNodes[i])->getChildName(origElemNode);
772               nodeC = (InlineFuncNode *)clones[i]->getChildByName(childName);
773             }
774           DEBTRACE("Assign container " << nodeC->getName() << "," << contCloned->getName())
775           nodeC->setContainer(contCloned);
776         }
777
778       // ended with current container
779       if(contCloned)
780         contCloned->decrRef();
781     }
782
783   DEBTRACE("End cloneAndPlaceNodesCoherently")
784   return clones;
785 }
786
787 void DynParaLoop::accept(Visitor *visitor)
788 {
789   visitor->visitDynParaLoop(this);
790 }
791
792 Node * DynParaLoop::getInitNode()
793 {
794   return _initNode;
795 }
796
797 Node * DynParaLoop::getExecNode()
798 {
799   return _node;
800 }
801
802 Node * DynParaLoop::getFinalizeNode()
803 {
804   return _finalizeNode;
805 }
806
807 void DynParaLoop::shutdown(int level)
808 {
809   if(level==0)return;
810   if(!_node) return;
811
812   std::vector<Node *>::iterator iter;
813   for (iter=_execNodes.begin() ; iter!=_execNodes.end() ; iter++)
814     (*iter)->shutdown(level);
815   for (iter=_execInitNodes.begin() ; iter!=_execInitNodes.end() ; iter++)
816     (*iter)->shutdown(level);
817   for (iter=_execFinalizeNodes.begin() ; iter!=_execFinalizeNodes.end() ; iter++)
818     (*iter)->shutdown(level);
819 }