1 // Copyright (C) 2006-2015 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "ComposedNode.hxx"
21 #include "LinkInfo.hxx"
22 #include "Container.hxx"
23 #include "InputPort.hxx"
24 #include "OutputPort.hxx"
25 #include "ServiceNode.hxx"
26 #include "InlineNode.hxx"
27 #include "DataFlowPort.hxx"
28 #include "DataStreamPort.hxx"
29 #include "ElementaryNode.hxx"
30 #include "ComponentInstance.hxx"
31 #include "ForEachLoop.hxx"
40 #include "YacsTrace.hxx"
42 using namespace YACS::ENGINE;
45 /*! \class YACS::ENGINE::ComposedNode
46 * \brief Base class for all composed nodes.
48 * This is an abstract class that must be specialized.
53 const char ComposedNode::SEP_CHAR_BTW_LEVEL[]=".";
55 ComposedNode::ComposedNode(const std::string& name):Node(name)
59 ComposedNode::ComposedNode(const ComposedNode& other, ComposedNode *father):Node(other,father)
63 ComposedNode::~ComposedNode()
67 void ComposedNode::performDuplicationOfPlacement(const Node& other)
69 const ComposedNode &otherC=*(dynamic_cast<const ComposedNode *>(&other));
70 DeploymentTree treeToDup=otherC.getDeploymentTree();
71 list< ElementaryNode * > clones=otherC.getRecursiveConstituents();
72 vector<Container *> conts=treeToDup.getAllContainers();
73 //iterate on all containers
74 for(vector<Container *>::iterator iterCt=conts.begin();iterCt!=conts.end();iterCt++)
76 vector<ComponentInstance *> comps=treeToDup.getComponentsLinkedToContainer(*iterCt);
77 Container *contCloned=0;
79 contCloned=(*iterCt)->clone();
81 //iterate on all component instances linked to the container
82 for(vector<ComponentInstance *>::iterator iterCp=comps.begin();iterCp!=comps.end();iterCp++)
84 vector<Task *> tasks=treeToDup.getTasksLinkedToComponent(*iterCp);
85 ComponentInstance *curCloned=(*iterCp)->clone();
86 curCloned->setContainer(contCloned);
87 for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
89 //No risk for static cast : appendTask called by ComposedNode.
90 list< ElementaryNode * >::iterator res=find(clones.begin(),clones.end(),(ElementaryNode *)(*iterT));
91 //No risk here to because called only on cloning process...
92 ServiceNode *nodeC=(ServiceNode *)getChildByName(otherC.getChildName(*res));
93 nodeC->setComponent(curCloned);
98 // iterate on all tasks linked to the container
99 vector<Task *> tasks=treeToDup.getTasksLinkedToContainer(*iterCt);
100 for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
102 std::list< ElementaryNode * >::iterator res=find(clones.begin(),clones.end(),(ElementaryNode *)(*iterT));
103 InlineFuncNode *nodeC=(InlineFuncNode *)getChildByName(otherC.getChildName(*res));
104 nodeC->setContainer(contCloned);
107 // ended with current container
109 contCloned->decrRef();
113 void ComposedNode::performShallowDuplicationOfPlacement(const Node& other)
115 const ComposedNode &otherC=*(dynamic_cast<const ComposedNode *>(&other));
116 DeploymentTree treeToDup=otherC.getDeploymentTree();
117 list< ElementaryNode * > clones=otherC.getRecursiveConstituents();
118 vector<Container *> conts=treeToDup.getAllContainers();
119 //iterate on all containers
120 for(vector<Container *>::iterator iterCt=conts.begin();iterCt!=conts.end();iterCt++)
122 vector<ComponentInstance *> comps=treeToDup.getComponentsLinkedToContainer(*iterCt);
123 Container *contCloned((*iterCt));
125 //iterate on all component instances linked to the container
126 for(vector<ComponentInstance *>::iterator iterCp=comps.begin();iterCp!=comps.end();iterCp++)
128 vector<Task *> tasks=treeToDup.getTasksLinkedToComponent(*iterCp);
129 ComponentInstance *curCloned((*iterCp));
130 curCloned->setContainer(contCloned);
131 for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
133 //No risk for static cast : appendTask called by ComposedNode.
134 list< ElementaryNode * >::iterator res=find(clones.begin(),clones.end(),(ElementaryNode *)(*iterT));
135 //No risk here to because called only on cloning process...
136 ServiceNode *nodeC=(ServiceNode *)getChildByName(otherC.getChildName(*res));
137 nodeC->setComponent(curCloned);
141 // iterate on all tasks linked to the container
142 vector<Task *> tasks=treeToDup.getTasksLinkedToContainer(*iterCt);
143 for(vector<Task *>::iterator iterT=tasks.begin();iterT!=tasks.end();iterT++)
145 std::list< ElementaryNode * >::iterator res=find(clones.begin(),clones.end(),(ElementaryNode *)(*iterT));
146 InlineFuncNode *nodeC=(InlineFuncNode *)getChildByName(otherC.getChildName(*res));
147 nodeC->setContainer(contCloned);
152 bool ComposedNode::isFinished()
154 if(_state==YACS::DONE)return true;
155 if(_state==YACS::ERROR)return true;
156 if(_state==YACS::FAILED)return true;
157 if(_state==YACS::DISABLED)return true;
161 void ComposedNode::init(bool start)
166 std::string ComposedNode::getName() const
168 return Node::getName();
171 std::string ComposedNode::getTaskName(Task *task) const
173 return getChildName(dynamic_cast<ElementaryNode *>(task));
176 //! Essentially for test. Use checkDeploymentTree instead to be sure that returned DeploymentTree is consistent.
177 DeploymentTree ComposedNode::getDeploymentTree() const
180 list< ElementaryNode * > tasks=getRecursiveConstituents();
181 for(list< ElementaryNode * >::iterator iter=tasks.begin();iter!=tasks.end();iter++)
182 ret.appendTask(*iter,(*iter)->getDynClonerIfExists(this));
186 //! Perform check of deployment consistency of the current graph.
188 * \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.
190 DeploymentTree ComposedNode::checkDeploymentTree(bool deep) const throw(YACS::Exception)
193 list< ElementaryNode * > tasks=getRecursiveConstituents();
194 for(list< ElementaryNode * >::iterator iter=tasks.begin();iter!=tasks.end();iter++)
196 switch(ret.appendTask(*iter,(*iter)->getDynClonerIfExists(this)))
198 case DeploymentTree::DUP_TASK_NOT_COMPATIBLE_WITH_EXISTING_TREE:
200 string what("ComposedNode::checkDeploymentTree : ServiceNode with name \""); what+=(*iter)->getName();
201 what+="\" coexists in a component with an another Task which context is incompatible with it.";
202 throw Exception(what);
204 case DeploymentTree::DEPLOYABLE_BUT_NOT_SPECIFIED :
208 string what("ComposedNode::checkDeploymentTree : ServiceNode with name \""); what+=(*iter)->getName();
209 what+="\" is deployable but no component is specified on it.";
210 throw Exception(what);
218 std::vector<Task *> ComposedNode::getNextTasks(bool& isMore)
227 //! Notify the node a task has emitted an event
230 * \note Runtime called method. Overloads the Scheduler::notifyFrom abstract method.
231 * Typically Called in Executor (in a parallel thread or not) by the Task 'task'
232 * to inform the scheduler that an event coded 'event' (in Executor static const var) happened.
233 * Contrary to updateStateFrom several levels may exist between 'sender' and 'this'.
235 * \param sender : task emitting event
236 * \param event : event emitted
238 * Called by Executor::functionForTaskExecution on YACS::FINISH event
240 * Called by Executor::launchTask on YACS::START event
242 * Calls ComposedNode::updateStateFrom to update state from task to root node
244 void ComposedNode::notifyFrom(const Task *sender, //* I : task emitting event
245 YACS::Event event, //* I : event emitted
246 const Executor *execInst
249 DEBTRACE("ComposedNode::notifyFrom " << event);
250 ElementaryNode *taskTyped=dynamic_cast<ElementaryNode *>((Task *)sender);
251 YACS::Event curEvent=event;
252 Node *lminus1LevelNode=taskTyped;
253 ComposedNode *curLevelNode=taskTyped->_father;
254 if(!curLevelNode)//Specific case of loop when 0 turn is specified without any enclosing bloc.
256 curEvent=curLevelNode->updateStateFrom(lminus1LevelNode,curEvent,execInst);
257 while(curEvent!=YACS::NOEVENT && curLevelNode!=this)
259 lminus1LevelNode=curLevelNode;
260 curLevelNode=curLevelNode->_father;
261 curEvent=curLevelNode->updateStateFrom(lminus1LevelNode,curEvent,execInst);
265 //! Add a dataflow link between two data ports.
267 * Precondition : 'start' AND 'end' are in/outputPort contained in a node in descendance of 'this'.
268 * \exception Exception : if incompatibility between input and output (type), or 'start'/'end'
269 * is/are NOT in/outputPort contained in a node in descendance
270 * of 'this', or a multiple link to an input not supporting it.
271 * \return true if a new link has been created, false otherwise.
274 bool ComposedNode::edAddLink(OutPort *start, InPort *end) throw(YACS::Exception)
276 DEBTRACE("ComposedNode::edAddLink");
277 set<OutPort *> represented;
279 start->getAllRepresented(represented);
280 if(represented.size()!=1)
283 for(set<OutPort *>::iterator iter=represented.begin();iter!=represented.end();iter++)
284 ret|=edAddLink(*iter,end);
287 if(start->isAlreadyLinkedWith(end))
289 ComposedNode* lwstCmnAnctr=getLowestCommonAncestor(start->getNode(),end->getNode());
290 list<ComposedNode *> allAscendanceOfNodeStart=start->getNode()->getAllAscendanceOf(lwstCmnAnctr);
291 list<ComposedNode *> allAscendanceOfNodeEnd=end->getNode()->getAllAscendanceOf(lwstCmnAnctr);
292 checkInMyDescendance(lwstCmnAnctr);
293 lwstCmnAnctr->checkLinkPossibility(start,allAscendanceOfNodeStart,end,allAscendanceOfNodeEnd);
295 if(dynamic_cast<ComposedNode *>(start->getNode()))
296 iterS=(ComposedNode *)start->getNode();
298 iterS=start->getNode()->_father;
299 pair<OutPort *, OutPort *> pO(start,start);
300 while(iterS!=lwstCmnAnctr)
302 iterS->buildDelegateOf(pO, end, allAscendanceOfNodeEnd);
303 iterS=iterS->_father;
305 if(dynamic_cast<ComposedNode *>(end->getNode()))
306 iterS=(ComposedNode *)end->getNode();
308 iterS=end->getNode()->_father;
310 InPort *currentPortI=end;
311 while(iterS!=lwstCmnAnctr)
313 iterS->buildDelegateOf(currentPortI, start, allAscendanceOfNodeStart);
314 iterS=iterS->_father;
316 bool ret=(pO.first)->addInPort(currentPortI);
317 end->edNotifyReferencedBy(pO.second);
321 //! Connect an OutPort to an InPort and add the necessary control link
323 * Connect the ports with a data link (edAddLink) and add
324 * a control flow link between the children of the lowest common ancestor node.
326 * \param start : the OutPort to connect
327 * \param end : the InPort to connect
328 * \return true if a new link has been created, false otherwise.
330 bool ComposedNode::edAddDFLink(OutPort *start, InPort *end) throw(YACS::Exception)
332 Node* n1=start->getNode();
333 Node* n2=end->getNode();
334 DEBTRACE( n1->getName() << ":" << n2->getName())
335 ComposedNode* father=getLowestCommonAncestor(n1,n2);
336 DEBTRACE( "ComposedNode::edAddDFLink: this="<<this->getName()
337 << " father=" << father->getName() )
338 DEBTRACE( "ComposedNode::edAddDFLink: OutPort=" << start->getName()
339 << " InPort=" << end->getName() )
342 bool ret = father->edAddDFLink(start,end); // special treatement for loop
346 throw Exception("Back link authorized only in special context (loop for example)");
348 bool ret= edAddLink(start,end);
351 //add a control link only if nodes are not in the same descendance
352 //if n1 == father (n2 is after n1) : the control link is not needed
353 //if n2 == father (n1 is after n2) : it's a back link authorized only in loop context
354 while(n1->getFather() != father)
356 while(n2->getFather() != father)
362 catch (Exception& ex)
364 // --- remove DF link already created in case of cycle dtection
365 DEBTRACE("Cycle detected, remove CF link");
366 if(start->isAlreadyLinkedWith(end))
367 edRemoveLink(start, end);
374 //! Add a controlflow link between two control ports.
376 * \note Precondition : 'start' AND 'end' are in/outGate contained in a node
377 * in DIRECT descendance of 'this'.
378 * \exception Exception : If a cycle has been detected, or incompatibility
379 * between input and output, or 'start'/'end' is/are NOT in/outputPort contained
380 * in a node in descendance of 'this', or a mutilple link to an input not
382 * \return true if a new link has been created, false otherwise.
384 bool ComposedNode::edAddLink(OutGate *start, InGate *end) throw(YACS::Exception)
386 Node* n1=start->getNode();
387 Node* n2=end->getNode();
389 throw Exception("ComposedNode::edAddLink: can not add a control link to a node with itself",1);
390 ComposedNode* father=checkHavingCommonFather(start->getNode(),end->getNode());
392 throw Exception("ComposedNode::edAddLink: Trying to add CF link on orphan nodes.");
395 checkInMyDescendance(father);
396 return father->edAddLink(start,end);
398 bool ret=start->edAddInGate(end);
402 checkNoCyclePassingThrough(end->getNode());
404 catch (Exception& ex)
406 // --- remove created CF link in case of cycle detection
407 DEBTRACE("Cycle detected, remove CF link");
408 edRemoveCFLink(start->getNode(), end->getNode());
414 //! Add a controlflow link between two nodes.
416 * Add a controlflow link between two nodes by calling edAddLink on their control ports
418 bool ComposedNode::edAddCFLink(Node *nodeS, Node *nodeE) throw(YACS::Exception)
420 return edAddLink(nodeS->getOutGate(),nodeE->getInGate());
423 //! Remove a controlflow link.
424 void ComposedNode::edRemoveCFLink(Node *nodeS, Node *nodeE) throw(YACS::Exception)
426 edRemoveLink(nodeS->getOutGate(),nodeE->getInGate());
429 //! Remove a dataflow link.
431 * Precondition : 'start' AND 'end' are in/outputPort contained in a node in descendance of 'this'.
433 * \exception Exception : If the specified link does not exist. The content of Exception
434 * is different in accordance with the link from 'start' to 'end'
435 * implies DF/DS gateway.
438 void ComposedNode::edRemoveLink(OutPort *start, InPort *end) throw(YACS::Exception)
440 if(!start->isAlreadyLinkedWith(end))
441 throw Exception("ComposedNode::edRemoveLink : unexisting link");
442 ComposedNode* lwstCmnAnctr=getLowestCommonAncestor(start->getNode(),end->getNode());
443 checkInMyDescendance(lwstCmnAnctr);
444 list<ComposedNode *> allAscendanceOfNodeStart=start->getNode()->getAllAscendanceOf(lwstCmnAnctr);
445 list<ComposedNode *> allAscendanceOfNodeEnd=end->getNode()->getAllAscendanceOf(lwstCmnAnctr);
447 // --- Part of test if the link from 'start' to 'end' really exist particulary all eventually intermediate ports created
449 ComposedNode *iterS=start->getNode()->_father;
450 pair<OutPort *,OutPort *> currentPortO(start,start);
451 vector<pair< ComposedNode * , pair < OutPort* , OutPort *> > > needsToDestroyO;
453 Node *nodeOTemp=start->getNode();
454 if(*nodeOTemp<*lwstCmnAnctr)
456 iterS=nodeOTemp->_father;
457 while(iterS!=lwstCmnAnctr)
462 what << "ComposedNode::edRemoveLink: "
463 << start->getNode()->getName() << "." <<start->getName() << "->"
464 << end->getNode()->getName() << "." << end->getName();
465 throw Exception(what.str());
467 OutPort *tmp=currentPortO.first;
468 iterS->getDelegateOf(currentPortO, end, allAscendanceOfNodeEnd);
469 needsToDestroyO.push_back(pair< ComposedNode * , pair < OutPort* , OutPort *> >(iterS,pair<OutPort* , OutPort *> (tmp,currentPortO.first)));
470 iterS=iterS->_father;
473 Node *nodeTemp=end->getNode();
474 InPort * currentPortI=end;
475 if(*nodeTemp<*lwstCmnAnctr)
477 iterS=nodeTemp->_father;
478 while(iterS!=lwstCmnAnctr)
483 what << "ComposedNode::edRemoveLink: "
484 << start->getNode()->getName() << "." <<start->getName() << "->"
485 << end->getNode()->getName() << "." << end->getName();
486 throw Exception(what.str());
488 iterS->getDelegateOf(currentPortI, start, allAscendanceOfNodeStart);
489 iterS=iterS->_father;
492 // --- End of test for evt intermediate ports created
494 (currentPortO.first)->removeInPort(currentPortI,false);
496 (currentPortO.second)->getAllRepresented(repr);
498 end->edNotifyDereferencedBy(currentPortO.second);
500 // --- Performing deletion of intermediate ports
502 iterS=start->getNode()->_father;
503 vector<pair< ComposedNode * , pair < OutPort* , OutPort *> > >::reverse_iterator iter;
504 for(iter=needsToDestroyO.rbegin();iter!=needsToDestroyO.rend();iter++)
505 (*iter).first->releaseDelegateOf(((*iter).second).first, ((*iter).second).second, end,allAscendanceOfNodeEnd);
506 nodeTemp=end->getNode();
507 if(*nodeTemp<*lwstCmnAnctr)
509 iterS=end->getNode()->_father;
511 while(iterS!=lwstCmnAnctr)
513 iterS->releaseDelegateOf(currentPortI, start, allAscendanceOfNodeStart);
514 iterS=iterS->_father;
519 //! Remove a controlflow link.
520 void ComposedNode::edRemoveLink(OutGate *start, InGate *end) throw(YACS::Exception)
522 ComposedNode* father=checkHavingCommonFather(start->getNode(),end->getNode());
524 throw Exception("edRemoveLink : nodes not in direct descendance of this");
525 start->edRemoveInGate(end);
528 bool ComposedNode::edAddChild(Node *DISOWNnode) throw(YACS::Exception)
530 return false; // --- reimplemented in derived classes
533 //! Remove a child node.
534 void ComposedNode::edRemoveChild(Node *node) throw(YACS::Exception)
538 if (node->_father!=this)
540 string what("node "); what+= node->getName() ; what+=" is not a child of node "; what += getName();
541 throw Exception(what);
543 node->edDisconnectAllLinksWithMe();
545 //set _modified flag so edUpdateState() can refresh state
549 //! Splits name globalName in 2 parts using separator.
551 * \note 'priority' specifies if during search process of 'separator' the max part is
552 * for 'firstPart' (priority=true) or 'lastPart' (priority=false).
554 * \throw Exception : 'lastPart' or 'firstPart' is empty.
555 * \return true if split process succeeds false otherwise (typically when character
556 * separator was not found).
558 bool ComposedNode::splitNamesBySep(const std::string& globalName, const char separator[],
559 std::string& firstPart, std::string& lastPart, bool priority) throw(YACS::Exception)
561 const string delims(separator);
562 string portName, nodeName;
563 string::size_type idx;
565 idx = globalName.find_last_of(delims);
567 idx = globalName.find_first_of(delims);
568 if (idx == string::npos)
570 firstPart=globalName;
574 firstPart = globalName.substr(0,idx);
575 lastPart = globalName.substr(idx+1);
576 if ((firstPart.empty()) || (lastPart.empty()))
578 string what("the name "); what+= globalName ; what+=" is not a valid port name";
579 throw Exception(what);
584 std::vector< std::pair<OutPort *, InPort *> > ComposedNode::getSetOfInternalLinks() const
586 vector< pair<OutPort *, InPort *> > ret;
587 list<OutPort *> temp=getSetOfOutPort();
588 for(list<OutPort *>::const_iterator iter2=temp.begin();iter2!=temp.end();iter2++)
590 set<InPort *> temp2=(*iter2)->edSetInPort();
591 for(set<InPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
592 if(isInMyDescendance((*iter3)->getNode()))
593 ret.push_back(pair<OutPort *, InPort *>((*iter2),(*iter3)));
598 std::vector< std::pair<OutPort *, InPort *> > ComposedNode::getSetOfLinksLeavingCurrentScope() const
600 vector< pair<OutPort *, InPort *> > ret;
601 std::set<OutPort *> ports=getAllOutPortsLeavingCurrentScope();
602 for(set<OutPort *>::iterator iter2=ports.begin();iter2!=ports.end();iter2++)
604 set<InPort *> temp2=(*iter2)->edSetInPort();
605 for(set<InPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
606 if(!isInMyDescendance((*iter3)->getNode()))
607 ret.push_back(pair<OutPort *, InPort *>(*iter2,*iter3));
612 void ComposedNode::checkConsistency(LinkInfo& info) const throw(YACS::Exception)
615 info.setPointOfView((ComposedNode *)this);
616 performCFComputations(info);
617 list<InputPort *> setOfInToTest=getSetOfInputPort();
618 for(list<InputPort *>::iterator iter1=setOfInToTest.begin();iter1!=setOfInToTest.end();iter1++)
620 vector<OutPort *> candidateForAdvCheck;
621 set<OutPort *> outPorts=(*iter1)->edSetOutPort();
622 //Filtering among outPorts, which of them, are candidates to fill *iter1 at the current scope.
623 for(set<OutPort *>::iterator iter2=outPorts.begin();iter2!=outPorts.end();iter2++)
625 (*iter2)->checkConsistency(info);
626 ComposedNode *manager=getLowestCommonAncestor((*iter2)->getNode(),(*iter1)->getNode());
627 if(isInMyDescendance(manager))
628 candidateForAdvCheck.push_back(*iter2);
630 if(!candidateForAdvCheck.empty())
631 //End of filtering. Now regarding CF constraints for the current InPutPort.
634 checkLinksCoherenceRegardingControl(candidateForAdvCheck,*iter1,info);
636 catch(YACS::Exception& ex)
638 std::string what=ex.what();
639 what += "\nfor input port: ";
640 what += (*iter1)->getNode()->getName();
642 what += (*iter1)->getName();
644 destructCFComputations(info);
645 throw YACS::Exception(what);
649 if(!(*iter1)->canBeNull() && !(*iter1)->edIsManuallyInitialized())
650 info.pushErrLink(0,*iter1,E_NEVER_SET_INPUTPORT);
652 destructCFComputations(info);
656 * This method check that G1 <- G2 <- G3 <- G1 does not happened.
657 * Typically called by methods that set a hierarchy (Bloc::edAddChild, Loop::edSetNode, ...).
659 void ComposedNode::checkNoCrossHierachyWith(Node *node) const throw(YACS::Exception)
661 ComposedNode *nodeC=dynamic_cast<ComposedNode *>(node);
664 list<ComposedNode *> ascendants=getAllAscendanceOf();
665 if(find(ascendants.begin(),ascendants.end(),nodeC)!=ascendants.end())
667 const char what[]="ComposedNode::checkNoCrossHierachyWith : ComposedNode with name \"";
668 string stream(what); stream+=node->getName(); stream+="\" is already in hierarchy ascendance of node with name \"";
669 stream+=_name; stream+="\" ; So it can't be now in its descendance !";
670 throw Exception(stream);
674 //! perform \b recursively all CF computations.
675 void ComposedNode::performCFComputations(LinkInfo& info) const
677 list<Node *> nodes=edGetDirectDescendants();
678 for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
679 if(dynamic_cast<ComposedNode *>(*iter))
680 ((ComposedNode *)(*iter))->performCFComputations(info);
683 //! destroy \b recursively all results of initial computations.
684 void ComposedNode::destructCFComputations(LinkInfo& info) const
686 list<Node *> nodes=edGetDirectDescendants();
687 for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
688 if(dynamic_cast<ComposedNode *>(*iter))
689 ((ComposedNode *)(*iter))->destructCFComputations(info);
693 * Returns the lowest Node (Elementary or Composed) (is sense of hierachy level ( operator< ) ) containing all 'ports'.
694 * Typically use in consistency computation.
695 * Precondition : 'ports' \b must contain at least one element. All elements of 'ports' should be in descendance of 'this'.
697 Node *ComposedNode::getLowestNodeDealingAll(const std::list<OutPort *>& ports) const
699 list< OutPort *>::const_iterator iter=ports.begin();
700 Node *ret=(*iter)->getNode();
702 for(;iter!=ports.end();iter++)
704 Node *tmp=(*iter)->getNode();
712 * call it only for 'starts' to 'end' links \b DEALED by 'this'.
714 void ComposedNode::checkLinksCoherenceRegardingControl(const std::vector<OutPort *>& starts, InputPort *end, LinkInfo& info) const throw(YACS::Exception)
716 map < ComposedNode *, list<OutPort *>, SortHierarc > outputs;//forward link classical
717 vector<OutPort *> outputsCross;//forward link cross
718 map < ComposedNode *, list<OutPort *>, SortHierarc > outputsBw;//backward
719 vector<OutPort *>::const_iterator iter1;
720 //vector<DataPort *> history=((*iter1).second)[0]->calculateHistoryOfLinkWith(end);
721 //DataPort *cross=DataPort::isCrossingType(history);
722 for(iter1=starts.begin();iter1!=starts.end();iter1++)
724 ComposedNode *manager=getLowestCommonAncestor((*iter1)->getNode(),end->getNode());
725 manager->checkControlDependancy((*iter1), end, false, outputs, outputsCross, outputsBw, info);
727 //Ok now let's regarding outputs all combinations : (outputs.size())*(outputs.size()-1)/2
728 unsigned char isAlreadyFed=FREE_ST;
729 //Dealing excusively with DS. Level is useless here because simultaneity is required for DS.
730 if(outputsCross.size()>0)
732 isAlreadyFed=FED_DS_ST;
733 if(outputsCross.size()>1)
734 for(vector< OutPort *>::const_iterator iter1=outputsCross.begin();iter1!=(outputsCross.end()-2);iter1++)
735 info.pushErrLink(*iter1,end,E_COLLAPSE_DS);
737 map < ComposedNode *, list<OutPort *>, SortHierarc >::iterator iter3=outputs.begin();
738 for(;iter3!=outputs.end();iter3++)
739 ((*iter3).first)->checkCFLinks((*iter3).second,end,isAlreadyFed,true,info);
740 if(isAlreadyFed==FREE_ST)
741 if(!end->edIsManuallyInitialized())
742 info.pushErrLink(0,end,E_ONLY_BACKWARD_DEFINED);
743 isAlreadyFed=FREE_ST;
745 map < ComposedNode *, list<OutPort *>, SortHierarc >::reverse_iterator iter5=outputsBw.rbegin();
746 for(;iter5!=outputsBw.rend();iter5++)
747 ((*iter5).first)->checkCFLinks((*iter5).second,end,isAlreadyFed,false,info);
751 * Internal method during CF links. This methode is in charge to statuate on links consistency in the case
752 * that no control flow defined by user is set.
754 void ComposedNode::solveObviousOrDelegateCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
756 static const char what[]="ComposedNode::solveObviousOrDelegateCFLinks : Internal error occured - uncorrect hierarchy detected !";
759 if(alreadyFed==FREE_ST)
762 info.pushInfoLink(*(starts.begin()),end,I_BACK);
765 else if(alreadyFed==FED_ST)
766 info.pushInfoLink(*(starts.begin()),end,direction ? I_USELESS : I_BACK_USELESS);
768 info.pushErrLink(*(starts.begin()),end,E_COLLAPSE_DFDS);
772 Node *levelOfDecision=getLowestNodeDealingAll(starts);
773 if(levelOfDecision==this)
774 throw Exception(what);
775 if(dynamic_cast<ElementaryNode *>(levelOfDecision))
778 if(alreadyFed==FREE_ST || alreadyFed==FED_ST)
780 if(alreadyFed==FREE_ST)
782 reason=direction ? W_COLLAPSE_EL : W_BACK_COLLAPSE_EL;
786 reason=direction ? W_COLLAPSE_EL_AND_USELESS : W_BACK_COLLAPSE_EL_AND_USELESS;
787 for(list< OutPort *>::const_iterator iter=starts.begin();iter!=starts.end();iter++)
788 info.pushWarnLink(*iter,end,reason);
792 ((ComposedNode *)levelOfDecision)->checkCFLinks(starts,end,alreadyFed,direction,info);
796 //! check control flow links
798 * \param starts If different of 0, must aggregate at leat \b 1 element.
800 * \param alreadyFed in/out parameter. Indicates if 'end' ports is already and surely set or fed by an another port.
801 * \param direction If true : forward direction else backward direction.
802 * \param info : informations collectedduring the check
804 void ComposedNode::checkCFLinks(const std::list<OutPort *>& starts, InputPort *end, unsigned char& alreadyFed, bool direction, LinkInfo& info) const
806 static const char what[]="ComposedNode::checkCFLinks : Internal error occured - uncorrect hierarchy detected !";
807 Node *nodeEnd=isInMyDescendance(end->getNode());
809 return solveObviousOrDelegateCFLinks(starts,end,alreadyFed,direction,info);
810 //This case is typically dedicated when direct son is ElementaryNode and self link is defined on this.
811 if(!dynamic_cast<ElementaryNode *>(nodeEnd))
812 throw Exception(what);
814 list< OutPort *>::const_iterator iter=starts.begin();
815 Node *nodeStart=(*iter)->getNode();
817 if(nodeEnd!=nodeStart)
818 throw Exception(what);
820 for(;iter!=starts.end();iter++)
821 if((*iter)->getNode()!=nodeStart)
822 throw Exception(what);
823 //Ok at this step we are sure that we have back links on the same elementary node.
825 for(iter=starts.begin();iter!=starts.end();iter++)
826 info.pushWarnLink(*iter,end,W_BACK_COLLAPSE_EL);
827 else//here no need to look at 'alreadyFed' var because it is waranteed to be equal to FREE_ST by construction.
828 info.pushInfoLink(*(starts.begin()),end,I_BACK);
832 std::vector< std::pair<InPort *, OutPort *> > ComposedNode::getSetOfLinksComingInCurrentScope() const
834 vector< pair<InPort *, OutPort *> > ret;
835 set<InPort *> ports=getAllInPortsComingFromOutsideOfCurrentScope();
836 for(set<InPort *>::iterator iter2=ports.begin();iter2!=ports.end();iter2++)
838 set<OutPort *> temp2=(*iter2)->edSetOutPort();
839 for(set<OutPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
841 if(isInMyDescendance((*iter3)->getNode()))continue;
842 std::set<OutPort *> trueOutPorts;
843 (*iter3)->getAllRepresented(trueOutPorts);
844 for(std::set<OutPort *>::iterator iter4=trueOutPorts.begin();iter4!=trueOutPorts.end();++iter4)
845 ret.push_back(pair<InPort *, OutPort *>(*iter2,*iter4));
851 //! List all output ports of children nodes that are linked to out of scope input ports
853 * \note List all output ports of nodes sons of 'this' that are linked to input ports
854 * of nodes not in descendance of 'this'.
855 * This method contrary to getAllInPortsComingFromOutsideOfCurrentScope is NOT virtual
856 * because for the moment all daughter classes have no more hidden YACS::ENGINE::OutPort.
858 std::set<OutPort *> ComposedNode::getAllOutPortsLeavingCurrentScope() const
861 list<OutPort *> temp=getSetOfOutPort();
862 for(list<OutPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
864 set<InPort *> temp2=(*iter2)->edSetInPort();
865 for(set<InPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
866 if(!isInMyDescendance((*iter3)->getNode()))
875 //! List all input ports that are linked to out of scope ports
878 * List all input ports of 'this' so that, for each it exists at least 1 link coming
879 * from outside to it.
882 std::set<InPort *> ComposedNode::getAllInPortsComingFromOutsideOfCurrentScope() const
885 list<InPort *> temp=getSetOfInPort();
886 for(list<InPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
888 set<OutPort *> temp2=(*iter2)->edSetOutPort();
889 for(set<OutPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
891 if(!isInMyDescendance((*iter3)->getNode()))
900 void ComposedNode::edDisconnectAllLinksWithMe()
904 Node::edDisconnectAllLinksWithMe();
907 vector< pair<OutPort *, InPort *> > linksToDestroy=getSetOfLinksLeavingCurrentScope();
908 vector< pair<OutPort *, InPort *> >::iterator iter;
909 for(iter=linksToDestroy.begin();iter!=linksToDestroy.end();iter++)
912 (*iter).first->removeInPort((*iter).second,true);
915 vector< pair<InPort *, OutPort *> > linksToDestroy2=getSetOfLinksComingInCurrentScope();
916 vector< pair<InPort *, OutPort *> >::iterator iter2;
917 for(iter2=linksToDestroy2.begin();iter2!=linksToDestroy2.end();iter2++)
920 (*iter2).second->removeInPort((*iter2).first,true);
924 ComposedNode *ComposedNode::getRootNode() const throw(YACS::Exception)
927 return (ComposedNode *)this;
928 return Node::getRootNode();
931 //! Check that Node 'node' is already a direct son of this.
932 bool ComposedNode::isNodeAlreadyAggregated(const Node *node) const
934 list<ComposedNode *> nodeAncestors = node->getAllAscendanceOf();
935 return find(nodeAncestors.begin(),nodeAncestors.end(),(ComposedNode *)this)!=nodeAncestors.end();
938 //! Returns the parent of a node that is the direct child of this node
940 * \note if 'nodeToTest'=='this' this is returned. Else if 'nodeToTest' is in descendance of
941 * 'this' the direct son is returned.
942 * Else 0 is returned.
944 * \param nodeToTest : the node to check
946 Node *ComposedNode::isInMyDescendance(Node *nodeToTest) const
950 if((ComposedNode *)nodeToTest==this)
952 Node *iterBack=nodeToTest;
953 ComposedNode *iter=nodeToTest->_father;
954 while(iter!=0 && iter!=this)
965 string ComposedNode::getChildName(const Node* node) const throw(YACS::Exception)
967 string nodeName=node->getQualifiedName();
968 if (!isNodeAlreadyAggregated(node))
970 if (node->getName() == "thisIsAFakeNode")
972 string child = node->getName()+".thisIsAFakeNode";
977 string what("node "); what+= node->getName() ; what+=" is not a child of node "; what += getName();
978 throw Exception(what);
982 const Node *father = node->_father;
983 while (father != this)
985 nodeName = father->getQualifiedName() + SEP_CHAR_BTW_LEVEL + nodeName;
986 father = father->_father;
991 std::string ComposedNode::getMyQualifiedName(const Node *directSon) const
993 return directSon->getName();
996 Node *ComposedNode::getChildByName(const std::string& name) const throw(YACS::Exception)
998 string potentiallyDirectSonName, remainsPath;
999 bool forwardNeeded=ComposedNode::splitNamesBySep(name, SEP_CHAR_BTW_LEVEL,
1000 potentiallyDirectSonName,remainsPath,false);
1001 Node *child=getChildByShortName(potentiallyDirectSonName);
1005 return child->getChildByName(remainsPath);
1008 //! Check if a node is in the descendance of this node
1010 * \note Check that 'nodeToTest' is in descendance of 'this' OR equal to 'this'
1011 * \exception Exception : If 'nodeToTest' is NOT in descendance of 'this' AND not equal to 'this'
1012 * \param nodeToTest : the node to check
1014 void ComposedNode::checkInMyDescendance(Node *nodeToTest) const throw(YACS::Exception)
1016 const char whatC[]=" is not the descendance of node ";
1019 string what("node "); what+= nodeToTest->getName(); what+=" ";
1020 what+=whatC; what+=_name;
1021 throw Exception(what);
1023 if((ComposedNode *)nodeToTest==this)
1025 ComposedNode *iter=nodeToTest->_father;
1026 while(iter!=0 && iter!=this)
1030 string what("node "); what+= nodeToTest->getName(); what+=" ";
1031 what+=whatC; what+=_name;
1032 throw Exception(what);
1036 //! Retrieves the lowest common ancestor of 2 nodes
1039 * \note Retrieves the lowest common ancestor of 'node1' AND 'node2'.
1040 * If 'node1' or 'node2' are both or indiscriminately instances of ComposedNode and that
1041 * 'node1' is in descendance of 'node2' (resp. 'node2' in descendance of 'node1')
1042 * 'node2' is returned (resp. 'node1').
1043 * \exception Exception : if 'node1' and 'node2' do not share the same genealogy.
1044 * \return The lowest common ancestor if it exists.
1047 ComposedNode *ComposedNode::getLowestCommonAncestor(Node *node1, Node *node2) throw(YACS::Exception)
1049 const char what[]="The two nodes do not share the same genealogy";
1050 if(node1==0 || node2==0)
1051 throw Exception(what);
1053 if(dynamic_cast<ComposedNode *>(node1))
1054 temp=(ComposedNode *)node1;//->_father;
1056 temp=(ComposedNode *)node1->_father;
1057 set<ComposedNode *> s;
1064 if(dynamic_cast<ComposedNode *>(node2))
1065 temp=(ComposedNode *)node2;//->_father;
1067 temp=(ComposedNode *)node2->_father;
1068 set<ComposedNode *>::iterator iter=s.find(temp);
1069 while(temp && iter==s.end())
1075 throw Exception(what);
1079 list<ElementaryNode *> ComposedNode::getRecursiveConstituents() const
1081 list<ElementaryNode *> ret;
1082 list<Node *> setOfNode=edGetDirectDescendants();
1083 for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1085 list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
1086 ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1091 //! Idem getAllRecursiveNodes, but this node is NOT included.
1092 list<Node *> ComposedNode::getAllRecursiveConstituents()
1095 list<Node *> setOfNode=edGetDirectDescendants();
1096 for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1098 if ( dynamic_cast<ComposedNode*> (*iter) )
1100 list<Node *> myCurrentSet=((ComposedNode*)(*iter))->getAllRecursiveConstituents();
1101 ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1102 ret.push_back(*iter);
1106 list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
1107 ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1113 //! Get all children nodes elementary and composed including this node
1114 list<Node *> ComposedNode::getAllRecursiveNodes()
1117 list<Node *> setOfNode=edGetDirectDescendants();
1118 for(list<Node *>::iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1120 if ( dynamic_cast<ElementaryNode*> (*iter) )
1122 list<ElementaryNode *> myCurrentSet=(*iter)->getRecursiveConstituents();
1123 ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1127 list<Node *> myCurrentSet=((ComposedNode*)(*iter))->getAllRecursiveNodes();
1128 ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1131 ret.push_back(this);
1136 //! Get the progress weight for all elementary nodes
1138 * Only elementary nodes have weight. If a node is in a for each loop, his weight is modified by the size of the loop
1141 list<pair<int,int> > ComposedNode::getProgressWeight()
1143 list<pair<int,int> > ret;
1144 list<Node *> setOfNode=edGetDirectDescendants();
1145 int elemDone, elemTotal;
1146 for(list<Node *>::const_iterator iter=setOfNode.begin();iter!=setOfNode.end();iter++)
1148 if ( dynamic_cast<ForEachLoop*> (*iter) )
1150 elemDone=((ForEachLoop*)(*iter))->getCurrentIndex();
1151 elemTotal=((ForEachLoop*)(*iter))->getNbOfElementsToBeProcessed();
1152 list<pair<int,int> > myCurrentSet=((ComposedNode*)(*iter))->getProgressWeight();
1153 myCurrentSet.pop_front();
1154 myCurrentSet.pop_back();
1155 for(list<pair<int,int> >::iterator iter=myCurrentSet.begin();iter!=myCurrentSet.end();iter++)
1157 (*iter).first=(*iter).second*elemDone;
1158 (*iter).second*=elemTotal;
1160 ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1162 else if ( dynamic_cast<ComposedNode*> (*iter) )
1164 list<pair<int,int> > myCurrentSet=((ComposedNode*)(*iter))->getProgressWeight();
1165 ret.insert(ret.end(),myCurrentSet.begin(),myCurrentSet.end());
1169 if ((*iter)->getState() == YACS::DONE)
1170 ret.push_back(pair<int,int>(1,1));
1172 ret.push_back(pair<int,int>(0,1));
1178 //! Get the input port name
1180 * get the input port name used by the current node, recursively built with children names.
1183 string ComposedNode::getInPortName(const InPort * inPort) const throw(YACS::Exception)
1185 return getPortName<InPort>(inPort);
1188 string ComposedNode::getOutPortName(const OutPort *outPort) const throw(YACS::Exception)
1190 return getPortName<OutPort>(outPort);
1193 int ComposedNode::getNumberOfInputPorts() const
1195 list<Node *> constituents=edGetDirectDescendants();
1197 for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1198 ret+=(*iter)->getNumberOfInputPorts();
1202 int ComposedNode::getNumberOfOutputPorts() const
1204 list<Node *> constituents=edGetDirectDescendants();
1206 for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1207 ret+=(*iter)->getNumberOfOutputPorts();
1211 list<InputPort *> ComposedNode::getSetOfInputPort() const
1213 list<Node *> constituents=edGetDirectDescendants();
1214 list<InputPort *> ret;
1215 for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1217 list<InputPort *> currentsPorts=(*iter)->getSetOfInputPort();
1218 ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1223 list<OutputPort *> ComposedNode::getSetOfOutputPort() const
1225 list<Node *> constituents=edGetDirectDescendants();
1226 list<OutputPort *> ret;
1227 for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1229 list<OutputPort *> currentsPorts=(*iter)->getSetOfOutputPort();
1230 ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1235 list<InputDataStreamPort *> ComposedNode::getSetOfInputDataStreamPort() const
1237 list<Node *> constituents=edGetDirectDescendants();
1238 list<InputDataStreamPort *> ret;
1239 for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1241 list<InputDataStreamPort *> currentsPorts=(*iter)->getSetOfInputDataStreamPort();
1242 ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1247 list<OutputDataStreamPort *> ComposedNode::getSetOfOutputDataStreamPort() const
1249 list<Node *> constituents=edGetDirectDescendants();
1250 list<OutputDataStreamPort *> ret;
1251 for(list<Node *>::iterator iter=constituents.begin();iter!=constituents.end();iter++)
1253 list<OutputDataStreamPort *> currentsPorts=(*iter)->getSetOfOutputDataStreamPort();
1254 ret.insert(ret.end(),currentsPorts.begin(),currentsPorts.end());
1259 OutPort *ComposedNode::getOutPort(const std::string& name) const throw(YACS::Exception)
1261 string portName, nodeName;
1262 if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false))
1264 Node *child = getChildByShortName(nodeName);
1265 return child->getOutPort(portName);
1269 string what("ComposedNode::getOutPort : the port with name "); what+=name; what+=" does not exist on the current level";
1270 throw Exception(what);
1274 //! Get an input port given its name
1276 * Contrary to YACS::ENGINE::ComposedNode::getOutputPort, this method is \b NOT recursive
1277 * and so the leaf of type ElementaryNode aggregating
1278 * this InputPort is directly invoked.
1280 InputPort * ComposedNode::getInputPort(const std::string& name) const throw(YACS::Exception)
1283 return Node::getInputPort(name);
1285 catch(Exception& e) {}
1287 string portName, nodeName;
1288 if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1290 Node *child = getChildByName(nodeName);
1291 return child->getInputPort(portName);
1295 string what("ComposedNode::getInputPort : the port with name "); what+=name; what+=" does not exist on the current level";
1296 throw Exception(what);
1300 //! Get an output port given its name
1302 * Contrary to YACS::ENGINE::ComposedNode::getInputPort, this method is recursive and go
1303 * down hierarchy step by step to complete its work.
1305 OutputPort * ComposedNode::getOutputPort(const std::string& name) const throw(YACS::Exception)
1307 string portName, nodeName;
1308 if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,false))
1310 Node *child = getChildByShortName(nodeName);
1311 return child->getOutputPort(portName);
1315 string what("ComposedNode::getOutputPort : the port with name "); what+=name; what+=" does not exist on the current level";
1316 throw Exception(what);
1320 InputDataStreamPort *ComposedNode::getInputDataStreamPort(const std::string& name) const throw(YACS::Exception)
1322 string portName, nodeName;
1323 if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1325 Node *child = getChildByName(nodeName);
1326 return child->getInputDataStreamPort(portName);
1330 string what("ComposedNode::getInputDataStreamPort : the port with name "); what+=name; what+=" does not exist on the current level";
1331 throw Exception(what);
1335 OutputDataStreamPort *ComposedNode::getOutputDataStreamPort(const std::string& name) const throw(YACS::Exception)
1337 string portName, nodeName;
1338 if(splitNamesBySep(name,Node::SEP_CHAR_IN_PORT,nodeName,portName,true))
1340 Node *child = getChildByName(nodeName);
1341 return child->getOutputDataStreamPort(portName);
1345 string what("ComposedNode::getOutputDataStreamPort : the port with name "); what+=name; what+=" does not exist on the current level";
1346 throw Exception(what);
1350 //! Update node state on receiving event from a node
1353 * \note Runtime called method. Perform, the state updating, from the son node 'node'
1354 * emitting the event 'event' (among Executor static const var).
1355 * WARNING Precondition : this == node->_father
1356 * \return The event (among Executor static const var) destinated to this->_father node
1357 * to perform eventually up level update.
1359 * Calls ComposedNode::updateStateOnStartEventFrom if event is YACS::START
1361 * Calls ComposedNode::updateStateOnFinishedEventFrom if event is YACS::FINISH
1363 * Called by ComposedNode::notifyFrom
1365 YACS::Event ComposedNode::updateStateFrom(Node *node, //* I : node emitting event
1366 YACS::Event event, //* I : event emitted
1367 const Executor *execInst
1370 DEBTRACE("updateStateFrom: " << node->getName() << " " << event);
1376 return updateStateOnStartEventFrom(node);
1379 return updateStateOnFinishedEventFrom(node);
1382 return updateStateOnFailedEventFrom(node,execInst);
1385 return YACS::NOEVENT;//TODO unexpected type of event
1389 catch(YACS::Exception& ex)
1391 //unexpected exception: probably a bug in engine
1392 //try to keep a consistent global state
1393 DEBTRACE( "updateStateFrom: " << ex.what() );
1394 _errorDetails="Internal error: ";
1395 _errorDetails=_errorDetails + ex.what();
1396 setState(YACS::ERROR);
1402 //unexpected exception: probably a bug in engine
1403 //try to keep a consistent global state
1404 setState(YACS::ERROR);
1410 //! Method used to notify the node that a child node has started
1412 * Update the ComposedNode state and return the ComposedNode change state
1414 * \param node : the child node that has started
1415 * \return the loop state change
1417 YACS::Event ComposedNode::updateStateOnStartEventFrom(Node *node)
1419 setState(YACS::ACTIVATED);
1423 //! Method used to notify the node that a child node has failed
1424 YACS::Event ComposedNode::updateStateOnFailedEventFrom(Node *node, const Executor *execInst)
1426 setState(YACS::FAILED);
1430 void ComposedNode::checkLinkPossibility(OutPort *start, const std::list<ComposedNode *>& pointsOfViewStart,
1431 InPort *end, const std::list<ComposedNode *>& pointsOfViewEnd) throw(YACS::Exception)
1433 if((dynamic_cast<DataFlowPort *>(start) || dynamic_cast<DataFlowPort *>(end))
1434 && (dynamic_cast<DataStreamPort *>(start) || dynamic_cast<DataStreamPort *>(end)))
1435 {//cross protocol required : deeper check needed
1437 list<ComposedNode *>::const_iterator iter;
1438 for(iter=pointsOfViewStart.begin();iter!=pointsOfViewStart.end() && !isOK;iter++)
1439 isOK=(*iter)->isRepeatedUnpredictablySeveralTimes();
1440 for(iter=pointsOfViewEnd.begin();iter!=pointsOfViewEnd.end() && !isOK;iter++)
1441 isOK=(*iter)->isRepeatedUnpredictablySeveralTimes();
1443 throw Exception("ComposedNode::checkLinkPossibility : Request for cross protocol link impossible.");
1447 void ComposedNode::buildDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView)
1451 void ComposedNode::buildDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView)
1455 void ComposedNode::getDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
1459 void ComposedNode::getDelegateOf(std::pair<OutPort *, OutPort *>& port, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
1463 void ComposedNode::releaseDelegateOf(InPort * & port, OutPort *initialStart, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
1467 void ComposedNode::releaseDelegateOf(OutPort *portDwn, OutPort *portUp, InPort *finalTarget, const std::list<ComposedNode *>& pointsOfView) throw(YACS::Exception)
1471 void ComposedNode::loaded()
1474 void ComposedNode::connected()
1478 void ComposedNode::accept(Visitor *visitor)
1480 list<Node *> constituents=edGetDirectDescendants();
1481 for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1483 (*iter)->accept(visitor);
1487 //! redefined on derived class of ComposedNode. by default a ComposedNode has no port by itself
1488 std::list<InputPort *> ComposedNode::getLocalInputPorts() const
1490 std::list<InputPort *> lip; return lip; // empty list
1493 //! redefined on derived class of ComposedNode. by default a ComposedNode has no port by itself
1494 std::list<OutputPort *> ComposedNode::getLocalOutputPorts() const
1496 std::list<OutputPort *> lop; return lop; // empty list
1499 bool ComposedNode::isNameAlreadyUsed(const std::string& name) const
1504 void ComposedNode::edUpdateState()
1506 DEBTRACE("ComposedNode::edUpdateState(): " << _state << " " << _modified);
1507 YACS::StatesForNode state=YACS::READY;
1511 checkBasicConsistency();
1516 state=YACS::INVALID;
1517 _errorDetails=e.what();
1519 DEBTRACE("ComposedNode::edUpdateState: " << _errorDetails);
1521 //update children if needed
1522 list<Node *> constituents=edGetDirectDescendants();
1523 for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1525 if(!(*iter)->isValid())
1526 state=YACS::INVALID;
1533 std::string ComposedNode::getErrorReport()
1535 DEBTRACE("ComposedNode::getErrorReport: " << getName() << " " << _state);
1536 YACS::StatesForNode effectiveState=getEffectiveState();
1538 if(effectiveState != YACS::INVALID && effectiveState != YACS::ERROR && effectiveState != YACS::FAILED)
1541 std::string report="<error node= " + getName();
1542 switch(effectiveState)
1545 report=report+" state= INVALID";
1548 report=report+" state= ERROR";
1551 report=report+" state= FAILED";
1556 report=report + ">\n" ;
1557 if(_errorDetails != "")
1558 report=report+_errorDetails+"\n";
1560 list<Node *> constituents=edGetDirectDescendants();
1561 for(list<Node *>::iterator iter=constituents.begin(); iter!=constituents.end(); iter++)
1563 std::string rep=(*iter)->getErrorReport();
1566 report=report+rep+"\n";
1569 report=report+"</error>";
1575 void ComposedNode::checkBasicConsistency() const throw(YACS::Exception)
1577 DEBTRACE("ComposedNode::checkBasicConsistency");
1578 std::list<InputPort *>::const_iterator iter;
1579 std::list<InputPort *> inports=getLocalInputPorts();
1580 for(iter=inports.begin();iter!=inports.end();iter++)
1581 (*iter)->checkBasicConsistency();
1584 //! Stop all pending activities of the composed node
1586 * This method should be called when a Proc is finished and must be deleted from the YACS server
1588 void ComposedNode::shutdown(int level)
1591 DEBTRACE("ComposedNode::shutdown");
1592 list<Node *> nodes=edGetDirectDescendants();
1593 for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
1594 (*iter)->shutdown(level);
1597 //! Clean the composed node in case of not clean exit
1599 * This method should be called on a control-c or sigterm
1601 void ComposedNode::cleanNodes()
1603 DEBTRACE("ComposedNode::cleanNodes");
1604 list<Node *> nodes=edGetDirectDescendants();
1605 for(list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
1606 (*iter)->cleanNodes();
1609 //! Reset the state of the node and its children depending on the parameter level
1610 void ComposedNode::resetState(int level)
1614 DEBTRACE("ComposedNode::resetState " << level << "," << _state);
1615 if( _state==YACS::ERROR || _state==YACS::FAILED || _state==YACS::ACTIVATED )
1617 Node::resetState(level);
1618 std::list<Node *> nodes=edGetDirectDescendants();
1619 for(std::list<Node *>::iterator iter=nodes.begin();iter!=nodes.end();iter++)
1620 (*iter)->resetState(level);