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