1 #include "ComposedNode.hxx"
2 #include "LinkInfo.hxx"
3 #include "Container.hxx"
4 #include "InputPort.hxx"
5 #include "OutputPort.hxx"
6 #include "ServiceNode.hxx"
7 #include "DataFlowPort.hxx"
8 #include "DataStreamPort.hxx"
9 #include "ElementaryNode.hxx"
10 #include "ComponentInstance.hxx"
19 #include "YacsTrace.hxx"
21 using namespace YACS::ENGINE;
24 const char ComposedNode::SEP_CHAR_BTW_LEVEL[]=".";
26 ComposedNode::ComposedNode(const std::string& name):Node(name)
30 ComposedNode::ComposedNode(const ComposedNode& other, ComposedNode *father):Node(other,father)
34 ComposedNode::~ComposedNode()
38 void ComposedNode::performDuplicationOfPlacement(const Node& other)
40 const ComposedNode &otherC=*(dynamic_cast<const ComposedNode *>(&other));
41 DeploymentTree treeToDup=otherC.getDeploymentTree();
42 list< ElementaryNode * > clones=otherC.getRecursiveConstituents();
43 vector<Container *> conts=treeToDup.getAllContainers();
44 for(vector<Container *>::iterator iterCt=conts.begin();iterCt!=conts.end();iterCt++)
46 vector<ComponentInstance *> comps=treeToDup.getComponentsLinkedToContainer(*iterCt);
47 Container *contCloned=0;
49 contCloned=(*iterCt)->clone();
50 for(vector<ComponentInstance *>::iterator iterCp=comps.begin();iterCp!=comps.end();iterCp++)
52 vector<Task *> tasks=treeToDup.getTasksLinkedToComponent(*iterCp);
53 ComponentInstance *curCloned=(*iterCp)->clone();
54 curCloned->setContainer(contCloned);
55 for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
57 //No risk for static cast : appendTask called by ComposedNode.
58 list< ElementaryNode * >::iterator res=find(clones.begin(),clones.end(),(ElementaryNode *)(*iterT));
59 //No risk here to because called only on cloning process...
60 ServiceNode *nodeC=(ServiceNode *)getChildByName(otherC.getChildName(*res));
61 nodeC->setComponent(curCloned);
66 contCloned->decrRef();
70 bool ComposedNode::isFinished()
72 if(_state==YACS::DONE)return true;
73 if(_state==YACS::ERROR)return true;
74 if(_state==YACS::FAILED)return true;
75 if(_state==YACS::DISABLED)return true;
79 void ComposedNode::init(bool start)
84 std::string ComposedNode::getName() const
86 return Node::getName();
89 std::string ComposedNode::getTaskName(Task *task) const
91 return getChildName(dynamic_cast<ElementaryNode *>(task));
94 //! Essentially for test. Use checkDeploymentTree instead to be sure that returned DeploymentTree is consistent.
95 DeploymentTree ComposedNode::getDeploymentTree() const
98 list< ElementaryNode * > tasks=getRecursiveConstituents();
99 for(list< ElementaryNode * >::iterator iter=tasks.begin();iter!=tasks.end();iter++)
100 ret.appendTask(*iter,(*iter)->getDynClonerIfExists(this));
104 //! Perform check of deployment consistency of the current graph.
106 * \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.
108 DeploymentTree ComposedNode::checkDeploymentTree(bool deep) const throw(Exception)
111 list< ElementaryNode * > tasks=getRecursiveConstituents();
112 for(list< ElementaryNode * >::iterator iter=tasks.begin();iter!=tasks.end();iter++)
114 switch(ret.appendTask(*iter,(*iter)->getDynClonerIfExists(this)))
116 case DeploymentTree::DUP_TASK_NOT_COMPATIBLE_WITH_EXISTING_TREE:
118 string what("ComposedNode::checkDeploymentTree : ServiceNode with name \""); what+=(*iter)->getName();
119 what+="\" coexists in a component with an another Task which context is incorrect with it.";
120 throw Exception(what);
122 case DeploymentTree::DEPLOYABLE_BUT_NOT_SPECIFIED :
126 string what("ComposedNode::checkDeploymentTree : ServiceNode with name \""); what+=(*iter)->getName();
127 what+="\" is deployable but no component is specified on it.";
128 throw Exception(what);
136 std::vector<Task *> ComposedNode::getNextTasks(bool& isMore)
145 //! Notify the node a task has emitted an event
148 * \note Runtime called method. Overloads the Scheduler::notifyFrom abstract method.
149 * Typically Called in Executor (in a parallel thread or not) by the Task 'task'
150 * to inform the scheduler that an event coded 'event' (in Executor static const var) happened.
151 * Contrary to updateStateFrom several levels may exist between 'sender' and 'this'.
153 * \param sender : task emitting event
154 * \param event : event emitted
156 * Called by Executor::functionForTaskExecution on YACS::FINISH event
158 * Called by Executor::launchTask on YACS::START event
160 * Calls ComposedNode::updateStateFrom to update state from task to root node
162 void ComposedNode::notifyFrom(const Task *sender, //* I : task emitting event
163 YACS::Event event //* I : event emitted
166 ElementaryNode *taskTyped=dynamic_cast<ElementaryNode *>((Task *)sender);
167 YACS::Event curEvent=event;
168 Node *lminus1LevelNode=taskTyped;
169 ComposedNode *curLevelNode=taskTyped->_father;
170 if(!curLevelNode)//Specific case of loop when 0 turn is specified without any enclosing bloc.
172 curEvent=curLevelNode->updateStateFrom(lminus1LevelNode,curEvent);
173 while(curEvent!=YACS::NOEVENT && curLevelNode!=this)
175 lminus1LevelNode=curLevelNode;
176 curLevelNode=curLevelNode->_father;
177 curEvent=curLevelNode->updateStateFrom(lminus1LevelNode,curEvent);
181 //! Add a dataflow link between two data ports.
183 * Precondition : 'start' AND 'end' are in/outputPort contained in a node in descendance of 'this'.
184 * \exception Exception : if incompatibility between input and output (type), or 'start'/'end'
185 * is/are NOT in/outputPort contained in a node in descendance
186 * of 'this', or a multiple link to an input not supporting it.
187 * \return true if a new link has been created, false otherwise.
190 bool ComposedNode::edAddLink(OutPort *start, InPort *end) throw(Exception)
192 DEBTRACE("ComposedNode::edAddLink");
193 set<OutPort *> represented;
195 start->getAllRepresented(represented);
196 if(represented.size()!=1)
199 for(set<OutPort *>::iterator iter=represented.begin();iter!=represented.end();iter++)
200 ret|=edAddLink(*iter,end);
203 if(start->isAlreadyLinkedWith(end))
205 ComposedNode* lwstCmnAnctr=getLowestCommonAncestor(start->getNode(),end->getNode());
206 list<ComposedNode *> allAscendanceOfNodeStart=start->getNode()->getAllAscendanceOf(lwstCmnAnctr);
207 list<ComposedNode *> allAscendanceOfNodeEnd=end->getNode()->getAllAscendanceOf(lwstCmnAnctr);
208 checkInMyDescendance(lwstCmnAnctr);
209 lwstCmnAnctr->checkLinkPossibility(start,allAscendanceOfNodeStart,end,allAscendanceOfNodeEnd);
211 if(dynamic_cast<ComposedNode *>(start->getNode()))
212 iterS=(ComposedNode *)start->getNode();
214 iterS=start->getNode()->_father;
215 pair<OutPort *, OutPort *> pO(start,start);
216 while(iterS!=lwstCmnAnctr)
218 iterS->buildDelegateOf(pO, end, allAscendanceOfNodeEnd);
219 iterS=iterS->_father;
221 if(dynamic_cast<ComposedNode *>(end->getNode()))
222 iterS=(ComposedNode *)end->getNode();
224 iterS=end->getNode()->_father;
226 InPort *currentPortI=end;
227 while(iterS!=lwstCmnAnctr)
229 iterS->buildDelegateOf(currentPortI, start, allAscendanceOfNodeStart);
230 iterS=iterS->_father;
232 bool ret=(pO.first)->addInPort(currentPortI);
233 end->edNotifyReferencedBy(pO.second);
237 //! Connect an OutPort to an InPort and add the necessary control link
239 * Connect the ports with a data link (edAddLink) and add
240 * a control flow link between the children of the lowest common ancestor node.
242 * \param start : the OutPort to connect
243 * \param end : the InPort to connect
244 * \return true if a new link has been created, false otherwise.
246 bool ComposedNode::edAddDFLink(OutPort *start, InPort *end) throw(Exception)
248 Node* n1=start->getNode();
249 Node* n2=end->getNode();
250 DEBTRACE( n1->getName() << ":" << n2->getName())
251 ComposedNode* father=getLowestCommonAncestor(n1,n2);
252 DEBTRACE( "ComposedNode::edAddDFLink: this="<<this->getName()
253 << " father=" << father->getName() )
254 DEBTRACE( "ComposedNode::edAddDFLink: OutPort=" << start->getName()
255 << " InPort=" << end->getName() )
258 bool ret = father->edAddDFLink(start,end); // special treatement for loop
262 throw Exception("Back link authorized only in special context (loop for example)");
264 bool ret= edAddLink(start,end);
267 //add a control link only if nodes are not in the same descendance
268 //if n1 == father (n2 is after n1) : the control link is not needed
269 //if n2 == father (n1 is after n2) : it's a back link authorized only in loop context
270 while(n1->getFather() != father)
272 while(n2->getFather() != father)
278 catch (Exception& ex)
280 // --- remove DF link already created in case of cycle dtection
281 DEBTRACE("Cycle detected, remove CF link");
282 if(start->isAlreadyLinkedWith(end))
283 edRemoveLink(start, end);
290 //! Add a controlflow link between two control ports.
292 * \note Precondition : 'start' AND 'end' are in/outGate contained in a node
293 * in DIRECT descendance of 'this'.
294 * \exception Exception : If a cycle has been detected, or incompatibility
295 * between input and output, or 'start'/'end' is/are NOT in/outputPort contained
296 * in a node in descendance of 'this', or a mutilple link to an input not
298 * \return true if a new link has been created, false otherwise.
300 bool ComposedNode::edAddLink(OutGate *start, InGate *end) throw(Exception)
302 Node* n1=start->getNode();
303 Node* n2=end->getNode();
305 throw Exception("ComposedNode::edAddLink: can not add a control link to a node with itself");
306 ComposedNode* father=checkHavingCommonFather(start->getNode(),end->getNode());
308 throw Exception("ComposedNode::edAddLink: Trying to add CF link on orphan nodes.");
311 checkInMyDescendance(father);
312 return father->edAddLink(start,end);
314 bool ret=start->edAddInGate(end);
318 checkNoCyclePassingThrough(end->getNode());
320 catch (Exception& ex)
322 // --- remove created CF link in case of cycle detection
323 DEBTRACE("Cycle detected, remove CF link");
324 edRemoveCFLink(start->getNode(), end->getNode());
330 //! Add a controlflow link between two nodes.
332 * Add a controlflow link between two nodes by calling edAddLink on their control ports
334 bool ComposedNode::edAddCFLink(Node *nodeS, Node *nodeE) throw(Exception)
336 return edAddLink(nodeS->getOutGate(),nodeE->getInGate());
339 //! Remove a controlflow link.
340 void ComposedNode::edRemoveCFLink(Node *nodeS, Node *nodeE) throw(Exception)
342 edRemoveLink(nodeS->getOutGate(),nodeE->getInGate());
345 //! Remove a dataflow link.
347 * Precondition : 'start' AND 'end' are in/outputPort contained in a node in descendance of 'this'.
349 * \exception Exception : If the specified link does not exist. The content of Exception
350 * is different in accordance with the link from 'start' to 'end'
351 * implies DF/DS gateway.
354 void ComposedNode::edRemoveLink(OutPort *start, InPort *end) throw(Exception)
356 if(!start->isAlreadyLinkedWith(end))
357 throw Exception("ComposedNode::edRemoveLink : unexisting link");
358 ComposedNode* lwstCmnAnctr=getLowestCommonAncestor(start->getNode(),end->getNode());
359 checkInMyDescendance(lwstCmnAnctr);
360 list<ComposedNode *> allAscendanceOfNodeStart=start->getNode()->getAllAscendanceOf(lwstCmnAnctr);
361 list<ComposedNode *> allAscendanceOfNodeEnd=end->getNode()->getAllAscendanceOf(lwstCmnAnctr);
363 // --- Part of test if the link from 'start' to 'end' really exist particulary all eventually intermediate ports created
365 ComposedNode *iterS=start->getNode()->_father;
366 pair<OutPort *,OutPort *> currentPortO(start,start);
367 vector<pair< ComposedNode * , pair < OutPort* , OutPort *> > > needsToDestroyO;
369 Node *nodeOTemp=start->getNode();
370 if(*nodeOTemp<*lwstCmnAnctr)
372 iterS=nodeOTemp->_father;
373 while(iterS!=lwstCmnAnctr)
378 what << "ComposedNode::edRemoveLink: "
379 << start->getNode()->getName() << "." <<start->getName() << "->"
380 << end->getNode()->getName() << "." << end->getName();
381 throw Exception(what.str());
383 OutPort *tmp=currentPortO.first;
384 iterS->getDelegateOf(currentPortO, end, allAscendanceOfNodeEnd);
385 needsToDestroyO.push_back(pair< ComposedNode * , pair < OutPort* , OutPort *> >(iterS,pair<OutPort* , OutPort *> (tmp,currentPortO.first)));
386 iterS=iterS->_father;
389 Node *nodeTemp=end->getNode();
390 InPort * currentPortI=end;
391 if(*nodeTemp<*lwstCmnAnctr)
393 iterS=nodeTemp->_father;
394 while(iterS!=lwstCmnAnctr)
399 what << "ComposedNode::edRemoveLink: "
400 << start->getNode()->getName() << "." <<start->getName() << "->"
401 << end->getNode()->getName() << "." << end->getName();
402 throw Exception(what.str());
404 iterS->getDelegateOf(currentPortI, start, allAscendanceOfNodeStart);
405 iterS=iterS->_father;
408 // --- End of test for evt intermediate ports created
410 (currentPortO.first)->removeInPort(currentPortI,false);
412 (currentPortO.second)->getAllRepresented(repr);
414 end->edNotifyDereferencedBy(currentPortO.second);
416 // --- Performing deletion of intermediate ports
418 iterS=start->getNode()->_father;
419 vector<pair< ComposedNode * , pair < OutPort* , OutPort *> > >::reverse_iterator iter;
420 for(iter=needsToDestroyO.rbegin();iter!=needsToDestroyO.rend();iter++)
421 (*iter).first->releaseDelegateOf(((*iter).second).first, ((*iter).second).second, end,allAscendanceOfNodeEnd);
422 nodeTemp=end->getNode();
423 if(*nodeTemp<*lwstCmnAnctr)
425 iterS=end->getNode()->_father;
427 while(iterS!=lwstCmnAnctr)
429 iterS->releaseDelegateOf(currentPortI, start, allAscendanceOfNodeStart);
430 iterS=iterS->_father;
435 //! Remove a controlflow link.
436 void ComposedNode::edRemoveLink(OutGate *start, InGate *end) throw(Exception)
438 ComposedNode* father=checkHavingCommonFather(start->getNode(),end->getNode());
440 throw Exception("edRemoveLink : nodes not in direct descendance of this");
441 start->edRemoveInGate(end);
444 //! Remove a child node.
445 void ComposedNode::edRemoveChild(Node *node) throw(Exception)
449 if (node->_father!=this)
451 string what("node "); what+= node->getName() ; what+=" is not a child of node "; what += getName();
452 throw Exception(what);
454 node->edDisconnectAllLinksWithMe();
456 //set _modified flag so edUpdateState() can refresh state
460 //! Splits name globalName in 2 parts using separator.
462 * \note 'priority' specifies if during search process of 'separator' the max part is
463 * for 'firstPart' (priority=true) or 'lastPart' (priority=false).
465 * \throw Exception : 'lastPart' or 'firstPart' is empty.
466 * \return true if split process succeeds false otherwise (typically when character
467 * separator was not found).
469 bool ComposedNode::splitNamesBySep(const std::string& globalName, const char separator[],
470 std::string& firstPart, std::string& lastPart, bool priority) throw(Exception)
472 const string delims(separator);
473 string portName, nodeName;
474 string::size_type idx;
476 idx = globalName.find_last_of(delims);
478 idx = globalName.find_first_of(delims);
479 if (idx == string::npos)
481 firstPart=globalName;
485 firstPart = globalName.substr(0,idx);
486 lastPart = globalName.substr(idx+1);
487 if ((firstPart.empty()) or (lastPart.empty()))
489 string what("the name "); what+= globalName ; what+=" is not a valid port name";
490 throw Exception(what);
495 std::vector< std::pair<OutPort *, InPort *> > ComposedNode::getSetOfInternalLinks() const
497 vector< pair<OutPort *, InPort *> > ret;
498 list<OutPort *> temp=getSetOfOutPort();
499 for(list<OutPort *>::const_iterator iter2=temp.begin();iter2!=temp.end();iter2++)
501 set<InPort *> temp2=(*iter2)->edSetInPort();
502 for(set<InPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
503 if(isInMyDescendance((*iter3)->getNode()))
504 ret.push_back(pair<OutPort *, InPort *>((*iter2),(*iter3)));
509 std::vector< std::pair<OutPort *, InPort *> > ComposedNode::getSetOfLinksLeavingCurrentScope() const
511 vector< pair<OutPort *, InPort *> > ret;
512 std::set<OutPort *> ports=getAllOutPortsLeavingCurrentScope();
513 for(set<OutPort *>::iterator iter2=ports.begin();iter2!=ports.end();iter2++)
515 set<InPort *> temp2=(*iter2)->edSetInPort();
516 for(set<InPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
517 if(!isInMyDescendance((*iter3)->getNode()))
518 ret.push_back(pair<OutPort *, InPort *>(*iter2,*iter3));
523 void ComposedNode::checkConsistency(LinkInfo& info) const throw(Exception)
526 info.setPointOfView((ComposedNode *)this);
527 performCFComputations(info);
528 list<InputPort *> setOfInToTest=getSetOfInputPort();
529 for(list<InputPort *>::iterator iter1=setOfInToTest.begin();iter1!=setOfInToTest.end();iter1++)
531 vector<OutPort *> candidateForAdvCheck;
532 set<OutPort *> outPorts=(*iter1)->edSetOutPort();
533 //Filtering among outPorts, which of them, are candidates to fill *iter1 at the current scope.
534 for(set<OutPort *>::iterator iter2=outPorts.begin();iter2!=outPorts.end();iter2++)
536 (*iter2)->checkConsistency(info);
537 ComposedNode *manager=getLowestCommonAncestor((*iter2)->getNode(),(*iter1)->getNode());
538 if(isInMyDescendance(manager))
539 candidateForAdvCheck.push_back(*iter2);
541 if(!candidateForAdvCheck.empty())
542 //End of filtering. Now regarding CF constraints for the current InPutPort.
543 checkLinksCoherenceRegardingControl(candidateForAdvCheck,*iter1,info);
546 if(!(*iter1)->edIsManuallyInitialized())
547 info.pushErrLink(0,*iter1,E_NEVER_SET_INPUTPORT);
549 destructCFComputations(info);
553 * This method check that G1 <- G2 <- G3 <- G1 does not happened.
554 * Typically called by methods that set a hierarchy (Bloc::edAddChild, Loop::edSetNode, ...).
556 void ComposedNode::checkNoCrossHierachyWith(Node *node) const throw (Exception)
558 ComposedNode *nodeC=dynamic_cast<ComposedNode *>(node);
561 list<ComposedNode *> ascendants=getAllAscendanceOf();
562 if(find(ascendants.begin(),ascendants.end(),nodeC)!=ascendants.end())
564 const char what[]="ComposedNode::checkNoCrossHierachyWith : ComposedNode with name \"";
565 string stream(what); stream+=node->getName(); stream+="\" is already in hierarchy ascendance of node with name \"";
566 stream+=_name; stream+="\" ; So it can't be now in its descendance !";
567 throw Exception(stream);
571 //! perform \b recursively all CF computations.
572 void ComposedNode::performCFComputations(LinkInfo& info) const
574 list<Node *> nodes=edGetDirectDescendants();
575 for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
576 if(dynamic_cast<ComposedNode *>(*iter))
577 ((ComposedNode *)(*iter))->performCFComputations(info);
580 //! destroy \b recursively all results of initial computations.
581 void ComposedNode::destructCFComputations(LinkInfo& info) const
583 list<Node *> nodes=edGetDirectDescendants();
584 for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
585 if(dynamic_cast<ComposedNode *>(*iter))
586 ((ComposedNode *)(*iter))->destructCFComputations(info);
590 * Returns the lowest Node (Elementary or Composed) (is sense of hierachy level ( operator< ) ) containing all 'ports'.
591 * Typically use in consistency computation.
592 * Precondition : 'ports' \b must contain at least one element. All elements of 'ports' should be in descendance of 'this'.
594 Node *ComposedNode::getLowestNodeDealingAll(const std::list<OutPort *>& ports) const
596 list< OutPort *>::const_iterator iter=ports.begin();
597 Node *ret=(*iter)->getNode();
599 for(;iter!=ports.end();iter++)
601 Node *tmp=(*iter)->getNode();
609 * call it only for 'starts' to 'end' links \b DEALED by 'this'.
611 void ComposedNode::checkLinksCoherenceRegardingControl(const std::vector<OutPort *>& starts, InputPort *end, LinkInfo& info) const throw(Exception)
613 map < ComposedNode *, list<OutPort *>, SortHierarc > outputs;//forward link classical
614 vector<OutPort *> outputsCross;//forward link cross
615 map < ComposedNode *, list<OutPort *>, SortHierarc > outputsBw;//backward
616 vector<OutPort *>::const_iterator iter1;
617 //vector<DataPort *> history=((*iter1).second)[0]->calculateHistoryOfLinkWith(end);
618 //DataPort *cross=DataPort::isCrossingType(history);
619 for(iter1=starts.begin();iter1!=starts.end();iter1++)
621 ComposedNode *manager=getLowestCommonAncestor((*iter1)->getNode(),end->getNode());
622 manager->checkControlDependancy((*iter1), end, false, outputs, outputsCross, outputsBw, info);
624 //Ok now let's regarding outputs all combinations : (outputs.size())*(outputs.size()-1)/2
625 unsigned char isAlreadyFed=FREE_ST;
626 //Dealing excusively with DS. Level is useless here because simultaneity is required for DS.
627 if(outputsCross.size()>0)
629 isAlreadyFed=FED_DS_ST;
630 if(outputsCross.size()>1)
631 for(vector< OutPort *>::const_iterator iter1=outputsCross.begin();iter1!=(outputsCross.end()-2);iter1++)
632 info.pushErrLink(*iter1,end,E_COLLAPSE_DS);
634 map < ComposedNode *, list<OutPort *>, SortHierarc >::iterator iter3=outputs.begin();
635 for(;iter3!=outputs.end();iter3++)
636 ((*iter3).first)->checkCFLinks((*iter3).second,end,isAlreadyFed,true,info);
637 if(isAlreadyFed==FREE_ST)
638 if(!end->edIsManuallyInitialized())
639 info.pushErrLink(0,end,E_ONLY_BACKWARD_DEFINED);
640 isAlreadyFed=FREE_ST;
642 map < ComposedNode *, list<OutPort *>, SortHierarc >::reverse_iterator iter5=outputsBw.rbegin();
643 for(;iter5!=outputsBw.rend();iter5++)
644 ((*iter5).first)->checkCFLinks((*iter5).second,end,isAlreadyFed,false,info);
648 * 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
651 void ComposedNode::solveObviousOrDelegateCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
653 static const char what[]="ComposedNode::solveObviousOrDelegateCFLinks : Internal error occured - uncorrect hierarchy detected !";
656 if(alreadyFed==FREE_ST)
659 info.pushInfoLink(*(starts.begin()),end,I_BACK);
662 else if(alreadyFed==FED_ST)
663 info.pushInfoLink(*(starts.begin()),end,direction ? I_USELESS : I_BACK_USELESS);
665 info.pushErrLink(*(starts.begin()),end,E_COLLAPSE_DFDS);
669 Node *levelOfDecision=getLowestNodeDealingAll(starts);
670 if(levelOfDecision==this)
671 throw Exception(what);
672 if(dynamic_cast<ElementaryNode *>(levelOfDecision))
675 if(alreadyFed==FREE_ST || alreadyFed==FED_ST)
677 if(alreadyFed==FREE_ST)
679 reason=direction ? W_COLLAPSE_EL : W_BACK_COLLAPSE_EL;
683 reason=direction ? W_COLLAPSE_EL_AND_USELESS : W_BACK_COLLAPSE_EL_AND_USELESS;
684 for(list< OutPort *>::const_iterator iter=starts.begin();iter!=starts.end();iter++)
685 info.pushWarnLink(*iter,end,reason);
689 ((ComposedNode *)levelOfDecision)->checkCFLinks(starts,end,alreadyFed,direction,info);
694 * \param starts If different of 0, must aggregate at leat \b 1 element.
695 * \param alreadyFed in/out parameter. Indicates if 'end' ports is already and surely set or fed by an another port.
696 * \param direction If true : forward direction else backward direction.
698 void ComposedNode::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
700 static const char what[]="ComposedNode::checkCFLinks : Internal error occured - uncorrect hierarchy detected !";
701 Node *nodeEnd=isInMyDescendance(end->getNode());
703 return solveObviousOrDelegateCFLinks(starts,end,alreadyFed,direction,info);
704 //This case is typically dedicated when direct son is ElementaryNode and self link is defined on this.
705 if(!dynamic_cast<ElementaryNode *>(nodeEnd))
706 throw Exception(what);
707 list< OutPort *>::const_iterator iter=starts.begin();
708 Node *nodeStart=(*iter)->getNode();
710 if(nodeEnd!=nodeStart)
711 throw Exception(what);
712 for(;iter!=starts.end();iter++)
713 if((*iter)->getNode()!=nodeStart)
714 throw Exception(what);
715 //Ok at this step we are sure that we have back links on the same elementary node.
717 for(iter=starts.begin();iter!=starts.end();iter++)
718 info.pushWarnLink(*iter,end,W_BACK_COLLAPSE_EL);
719 else//here no need to look at 'alreadyFed' var because it is waranteed to be equal to FREE_ST by construction.
720 info.pushInfoLink(*(starts.begin()),end,I_BACK);
724 std::vector< std::pair<InPort *, OutPort *> > ComposedNode::getSetOfLinksComingInCurrentScope() const
726 vector< pair<InPort *, OutPort *> > ret;
727 set<InPort *> ports=getAllInPortsComingFromOutsideOfCurrentScope();
728 for(set<InPort *>::iterator iter2=ports.begin();iter2!=ports.end();iter2++)
730 set<OutPort *> temp2=(*iter2)->edSetOutPort();
731 for(set<OutPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
732 if(!isInMyDescendance((*iter3)->getNode()))
733 ret.push_back(pair<InPort *, OutPort *>(*iter2,*iter3));
738 //! List all output ports of children nodes that are linked to out of scope input ports
740 * \note List all output ports of nodes sons of 'this' that are linked to input ports
741 * of nodes not in descendance of 'this'.
742 * This method contrary to getAllInPortsComingFromOutsideOfCurrentScope is NOT virtual
743 * because for the moment all daughter classes have no more hidden YACS::ENGINE::OutPort.
745 std::set<OutPort *> ComposedNode::getAllOutPortsLeavingCurrentScope() const
748 list<OutPort *> temp=getSetOfOutPort();
749 for(list<OutPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
751 set<InPort *> temp2=(*iter2)->edSetInPort();
752 for(set<InPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
753 if(!isInMyDescendance((*iter3)->getNode()))
762 //! List all input ports that are linked to out of scope ports
765 * List all input ports of 'this' so that, for each it exists at least 1 link coming
766 * from outside to it.
769 std::set<InPort *> ComposedNode::getAllInPortsComingFromOutsideOfCurrentScope() const
772 list<InPort *> temp=getSetOfInPort();
773 for(list<InPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
775 set<OutPort *> temp2=(*iter2)->edSetOutPort();
776 for(set<OutPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
778 if(!isInMyDescendance((*iter3)->getNode()))
787 void ComposedNode::edDisconnectAllLinksWithMe()
791 Node::edDisconnectAllLinksWithMe();
794 vector< pair<OutPort *, InPort *> > linksToDestroy=getSetOfLinksLeavingCurrentScope();
795 vector< pair<OutPort *, InPort *> >::iterator iter;
796 for(iter=linksToDestroy.begin();iter!=linksToDestroy.end();iter++)
799 (*iter).first->removeInPort((*iter).second,true);
802 vector< pair<InPort *, OutPort *> > linksToDestroy2=getSetOfLinksComingInCurrentScope();
803 vector< pair<InPort *, OutPort *> >::iterator iter2;
804 for(iter2=linksToDestroy2.begin();iter2!=linksToDestroy2.end();iter2++)
807 (*iter2).second->removeInPort((*iter2).first,true);
811 ComposedNode *ComposedNode::getRootNode() const throw(Exception)
814 return (ComposedNode *)this;
815 return Node::getRootNode();
818 //! Check that Node 'node' is already a direct son of this.
819 bool ComposedNode::isNodeAlreadyAggregated(const Node *node) const
821 list<ComposedNode *> nodeAncestors = node->getAllAscendanceOf();
822 return find(nodeAncestors.begin(),nodeAncestors.end(),(ComposedNode *)this)!=nodeAncestors.end();
825 //! Returns the parent of a node that is the direct child of this node
827 * \note if 'nodeToTest'=='this' this is returned. Else if 'nodeToTest' is in descendance of
828 * 'this' the direct son is returned.
829 * Else 0 is returned.
831 * \param nodeToTest : the node to check
833 Node *ComposedNode::isInMyDescendance(Node *nodeToTest) const
837 if((ComposedNode *)nodeToTest==this)
839 Node *iterBack=nodeToTest;
840 ComposedNode *iter=nodeToTest->_father;
841 while(iter!=0 && iter!=this)
852 string ComposedNode::getChildName(const Node* node) const throw(Exception)
854 string nodeName=node->getQualifiedName();
855 if (!isNodeAlreadyAggregated(node))
857 if (node->getName() == "thisIsAFakeNode")
859 string child = node->getName()+".thisIsAFakeNode";
864 string what("node "); what+= node->getName() ; what+=" is not a child of node "; what += getName();
865 throw Exception(what);
869 const Node *father = node->_father;
870 while (father != this)
872 nodeName = father->getQualifiedName() + SEP_CHAR_BTW_LEVEL + nodeName;
873 father = father->_father;
878 std::string ComposedNode::getMyQualifiedName(const Node *directSon) const
880 return directSon->getName();
883 Node *ComposedNode::getChildByName(const std::string& name) const throw(Exception)
885 string potentiallyDirectSonName, remainsPath;
886 bool forwardNeeded=ComposedNode::splitNamesBySep(name, SEP_CHAR_BTW_LEVEL,
887 potentiallyDirectSonName,remainsPath,false);
888 Node *child=getChildByShortName(potentiallyDirectSonName);
892 return child->getChildByName(remainsPath);
895 //! Check if a node is in the descendance of this node
897 * \note Check that 'nodeToTest' is in descendance of 'this' OR equal to 'this'
898 * \exception Exception : If 'nodeToTest' is NOT in descendance of 'this' AND not equal to 'this'
899 * \param nodeToTest : the node to check
901 void ComposedNode::checkInMyDescendance(Node *nodeToTest) const throw(Exception)
903 const char whatC[]=" is not the descendance of node ";
906 string what("node "); what+= nodeToTest->getName(); what+=" ";
907 what+=whatC; what+=_name;
908 throw Exception(what);
910 if((ComposedNode *)nodeToTest==this)
912 ComposedNode *iter=nodeToTest->_father;
913 while(iter!=0 && iter!=this)
917 string what("node "); what+= nodeToTest->getName(); what+=" ";
918 what+=whatC; what+=_name;
919 throw Exception(what);
923 //! Retrieves the lowest common ancestor of 2 nodes
926 * \note Retrieves the lowest common ancestor of 'node1' AND 'node2'.
927 * If 'node1' or 'node2' are both or indiscriminately instances of ComposedNode and that
928 * 'node1' is in descendance of 'node2' (resp. 'node2' in descendance of 'node1')
929 * 'node2' is returned (resp. 'node1').
930 * \exception Exception : if 'node1' and 'node2' do not share the same genealogy.
931 * \return The lowest common ancestor if it exists.
934 ComposedNode *ComposedNode::getLowestCommonAncestor(Node *node1, Node *node2) throw(Exception)
936 const char what[]="2 nodes does not share the same genealogy";
937 if(node1==0 || node2==0)
938 throw Exception(what);
940 if(dynamic_cast<ComposedNode *>(node1))
941 temp=(ComposedNode *)node1;//->_father;
943 temp=(ComposedNode *)node1->_father;
944 set<ComposedNode *> s;
951 if(dynamic_cast<ComposedNode *>(node2))
952 temp=(ComposedNode *)node2;//->_father;
954 temp=(ComposedNode *)node2->_father;
955 set<ComposedNode *>::iterator iter=s.find(temp);
956 while(temp && iter==s.end())
962 throw Exception(what);
966 list<ElementaryNode *> ComposedNode::getRecursiveConstituents() const
968 list<ElementaryNode *> ret;
969 list<Node *> setOfNode=edGetDirectDescendants();
970 for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
972 list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
973 ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
978 //! Idem getAllRecursiveNodes, but this node is NOT included.
979 list<Node *> ComposedNode::getAllRecursiveConstituents()
982 list<Node *> setOfNode=edGetDirectDescendants();
983 for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
985 if ( dynamic_cast<ComposedNode*> (*iter) )
987 list<Node *> myCurrentSet=((ComposedNode*)(*iter))->getAllRecursiveConstituents();
988 ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
989 ret.push_back(*iter);
993 list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
994 ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1000 //! Get all children nodes elementary and composed including this node
1001 list<Node *> ComposedNode::getAllRecursiveNodes()
1004 list<Node *> setOfNode=edGetDirectDescendants();
1005 for(list<Node *>::iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1007 if ( dynamic_cast<ElementaryNode*> (*iter) )
1009 list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
1010 ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1014 list<Node *> myCurrentSet=((ComposedNode*)(*iter))->getAllRecursiveNodes();
1015 ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1018 ret.push_back(this);
1022 //! Get the input port name
1024 * get the input port name used by the current node, recursively built with children names.
1027 string ComposedNode::getInPortName(const InPort * inPort) const throw (Exception)
1029 return getPortName<InPort>(inPort);
1032 string ComposedNode::getOutPortName(const OutPort *outPort) const throw (Exception)
1034 return getPortName<OutPort>(outPort);
1037 int ComposedNode::getNumberOfInputPorts() const
1039 list<Node *> constituents=edGetDirectDescendants();
1041 for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1042 ret+=(*iter)->getNumberOfInputPorts();
1046 int ComposedNode::getNumberOfOutputPorts() const
1048 list<Node *> constituents=edGetDirectDescendants();
1050 for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1051 ret+=(*iter)->getNumberOfOutputPorts();
1055 list<InputPort *> ComposedNode::getSetOfInputPort() const
1057 list<Node *> constituents=edGetDirectDescendants();
1058 list<InputPort *> ret;
1059 for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1061 list<InputPort *> currentsPorts=(*iter)->getSetOfInputPort();
1062 ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1067 list<OutputPort *> ComposedNode::getSetOfOutputPort() const
1069 list<Node *> constituents=edGetDirectDescendants();
1070 list<OutputPort *> ret;
1071 for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1073 list<OutputPort *> currentsPorts=(*iter)->getSetOfOutputPort();
1074 ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1079 list<InputDataStreamPort *> ComposedNode::getSetOfInputDataStreamPort() const
1081 list<Node *> constituents=edGetDirectDescendants();
1082 list<InputDataStreamPort *> ret;
1083 for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1085 list<InputDataStreamPort *> currentsPorts=(*iter)->getSetOfInputDataStreamPort();
1086 ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1091 list<OutputDataStreamPort *> ComposedNode::getSetOfOutputDataStreamPort() const
1093 list<Node *> constituents=edGetDirectDescendants();
1094 list<OutputDataStreamPort *> ret;
1095 for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1097 list<OutputDataStreamPort *> currentsPorts=(*iter)->getSetOfOutputDataStreamPort();
1098 ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1103 OutPort *ComposedNode::getOutPort(const std::string& name) const throw(Exception)
1105 string portName, nodeName;
1106 if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false))
1108 Node *child = getChildByShortName(nodeName);
1109 return child->getOutPort(portName);
1113 string what("ComposedNode::getOutPort : the port with name "); what+=name; what+=" does not exist on the current level";
1114 throw Exception(what);
1118 //! Get an input port given its name
1120 * Contrary to YACS::ENGINE::ComposedNode::getOutputPort, this method is \b NOT recursive
1121 * and so the leaf of type ElementaryNode aggregating
1122 * this InputPort is directly invoked.
1124 InputPort * ComposedNode::getInputPort(const std::string& name) const throw(Exception)
1126 string portName, nodeName;
1127 if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1129 Node *child = getChildByName(nodeName);
1130 return child->getInputPort(portName);
1134 string what("ComposedNode::getInputPort : the port with name "); what+=name; what+=" does not exist on the current level";
1135 throw Exception(what);
1139 //! Get an output port given its name
1141 * Contrary to YACS::ENGINE::ComposedNode::getInputPort, this method is recursive and go
1142 * down hierarchy step by step to complete its work.
1144 OutputPort * ComposedNode::getOutputPort(const std::string& name) const throw(Exception)
1146 string portName, nodeName;
1147 if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false))
1149 Node *child = getChildByShortName(nodeName);
1150 return child->getOutputPort(portName);
1154 string what("ComposedNode::getOutputPort : the port with name "); what+=name; what+=" does not exist on the current level";
1155 throw Exception(what);
1159 InputDataStreamPort *ComposedNode::getInputDataStreamPort(const std::string& name) const throw(Exception)
1161 string portName, nodeName;
1162 if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1164 Node *child = getChildByName(nodeName);
1165 return child->getInputDataStreamPort(portName);
1169 string what("ComposedNode::getInputDataStreamPort : the port with name "); what+=name; what+=" does not exist on the current level";
1170 throw Exception(what);
1174 OutputDataStreamPort *ComposedNode::getOutputDataStreamPort(const std::string& name) const throw(Exception)
1176 string portName, nodeName;
1177 if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1179 Node *child = getChildByName(nodeName);
1180 return child->getOutputDataStreamPort(portName);
1184 string what("ComposedNode::getOutputDataStreamPort : the port with name "); what+=name; what+=" does not exist on the current level";
1185 throw Exception(what);
1189 //! Update node state on receiving event from a node
1192 * \note Runtime called method. Perform, the state updating, from the son node 'node'
1193 * emitting the event 'event' (among Executor static const var).
1194 * WARNING Precondition : this == node->_father
1195 * \return The event (among Executor static const var) destinated to this->_father node
1196 * to perform eventually up level update.
1198 * Calls ComposedNode::updateStateOnStartEventFrom if event is YACS::START
1200 * Calls ComposedNode::updateStateOnFinishedEventFrom if event is YACS::FINISH
1202 * Called by ComposedNode::notifyFrom
1204 YACS::Event ComposedNode::updateStateFrom(Node *node, //* I : node emitting event
1205 YACS::Event event //* I : event emitted
1208 DEBTRACE("updateStateFrom: " << node->getName() << " " << event);
1214 return updateStateOnStartEventFrom(node);
1217 return updateStateOnFinishedEventFrom(node);
1220 return updateStateOnFailedEventFrom(node);
1223 return YACS::NOEVENT;//TODO unexpected type of event
1227 catch(YACS::Exception& ex)
1229 //unexpected exception: probably a bug in engine
1230 //try to keep a consistent global state
1231 DEBTRACE( "updateStateFrom: " << ex.what() );
1232 setState(YACS::ERROR);
1238 //unexpected exception: probably a bug in engine
1239 //try to keep a consistent global state
1240 setState(YACS::ERROR);
1246 //! Method used to notify the node that a child node has started
1248 * Update the ComposedNode state and return the ComposedNode change state
1250 * \param node : the child node that has started
1251 * \return the loop state change
1253 YACS::Event ComposedNode::updateStateOnStartEventFrom(Node *node)
1255 setState(YACS::ACTIVATED);
1259 //! Method used to notify the node that a child node has failed
1260 YACS::Event ComposedNode::updateStateOnFailedEventFrom(Node *node)
1262 setState(YACS::FAILED);
1266 void ComposedNode::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
1267 InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(Exception)
1269 if((dynamic_cast<DataFlowPort *>(start) or dynamic_cast<DataFlowPort *>(end))
1270 and (dynamic_cast<DataStreamPort *>(start) or dynamic_cast<DataStreamPort *>(end)))
1271 {//cross protocol required : deeper check needed
1273 list<ComposedNode *>::const_iterator iter;
1274 for(iter=pointsOfViewStart.begin();iter!=pointsOfViewStart.end() and !isOK;iter++)
1275 isOK=(*iter)->isRepeatedUnpredictablySeveralTimes();
1276 for(iter=pointsOfViewEnd.begin();iter!=pointsOfViewEnd.end() and !isOK;iter++)
1277 isOK=(*iter)->isRepeatedUnpredictablySeveralTimes();
1279 throw Exception("ComposedNode::checkLinkPossibility : Request for cross protocol link impossible.");
1283 void ComposedNode::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
1287 void ComposedNode::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
1291 void ComposedNode::getDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView) throw(Exception)
1295 void ComposedNode::getDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(Exception)
1299 void ComposedNode::releaseDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView) throw(Exception)
1303 void ComposedNode::releaseDelegateOf(OutPort *portDwn, OutPort *portUp, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(Exception)
1307 void ComposedNode::loaded()
1311 void ComposedNode::accept(Visitor *visitor)
1313 list<Node *> constituents=edGetDirectDescendants();
1314 for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1316 (*iter)->accept(visitor);
1320 //! redefined on derived class of ComposedNode. by default a ComposedNode has no port by itself
1321 std::list<InputPort *> ComposedNode::getLocalInputPorts() const
1323 std::list<InputPort *> lip; return lip; // empty list
1326 //! redefined on derived class of ComposedNode. by default a ComposedNode has no port by itself
1327 std::list<OutputPort *> ComposedNode::getLocalOutputPorts() const
1329 std::list<OutputPort *> lop; return lop; // empty list
1332 bool ComposedNode::isNameAlreadyUsed(const std::string& name) const
1337 void ComposedNode::edUpdateState()
1339 DEBTRACE("ComposedNode::edUpdateState(): " << _state << " " << _modified);
1340 YACS::StatesForNode state=YACS::READY;
1342 //update children if needed
1343 list<Node *> constituents=edGetDirectDescendants();
1344 for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1346 if(!(*iter)->isValid())
1347 state=YACS::INVALID;
1354 std::string ComposedNode::getErrorReport()
1356 DEBTRACE("ComposedNode::getErrorReport: " << getName() << " " << _state);
1357 YACS::StatesForNode effectiveState=getEffectiveState();
1358 if(effectiveState == YACS::READY || effectiveState == YACS::DONE)
1361 std::string report="<error node= " + getName();
1362 switch(effectiveState)
1365 report=report+" state= INVALID";
1368 report=report+" state= ERROR";
1371 report=report+" state= FAILED";
1376 report=report + ">\n" ;
1377 if(_errorDetails != "")
1378 report=report+_errorDetails+"\n";
1380 list<Node *> constituents=edGetDirectDescendants();
1381 for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1383 std::string rep=(*iter)->getErrorReport();
1386 report=report+rep+"\n";
1389 report=report+"</error>";