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