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