2 #include "InputPort.hxx"
3 #include "OutputPort.hxx"
4 #include "ComposedNode.hxx"
5 #include "Dispatcher.hxx"
6 #include "InputDataStreamPort.hxx"
7 #include "OutputDataStreamPort.hxx"
11 #include "YacsTrace.hxx"
13 using namespace YACS::ENGINE;
16 const char Node::SEP_CHAR_IN_PORT[]=".";
19 std::map<int,Node*> Node::idMap;
21 Node::Node(const std::string& name):_name(name),_inGate(this),_outGate(this),_father(0),_state(YACS::READY),
22 _implementation(Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME),_modified(1)
24 // Should be protected by lock ??
29 Node::Node(const Node& other, ComposedNode *father):_inGate(this),_outGate(this),_name(other._name),_father(father),
30 _state(YACS::READY),_implementation(other._implementation),
31 _propertyMap(other._propertyMap),_modified(other._modified)
42 * initialisation of all input and output ports and gates, for execution
45 void Node::init(bool start)
49 if(_state == YACS::DISABLED)
51 exDisabledState(); // to refresh propagation of DISABLED state
54 setState(YACS::READY);
57 Node *Node::clone(ComposedNode *father, bool editionOnly) const
59 Node *ret=simpleClone(father,editionOnly);
60 ret->performDuplicationOfPlacement(*this);
64 //! Change the name of the node
66 * raise an exception if the name is already used in the scope of its father
67 * \param name : the new name
69 void Node::setName(const std::string& name)
73 if(_father->isNameAlreadyUsed(name))
75 if ( _father->getChildByName(name) != this )
77 std::string what("Name ");
79 what+=" already exists in the scope of "; what+=_father->getName();
80 throw Exception(what);
88 * get the set of all nodes connected to the outGate
91 set<Node *> Node::getOutNodes() const
94 set<InGate *> inGates=_outGate.edSetInGate();
95 for(set<InGate *>::iterator iter=inGates.begin();iter!=inGates.end();iter++)
96 ret.insert((*iter)->getNode());
100 bool Node::exIsControlReady() const
102 return _inGate.exIsReady();
105 //! Update the node state
107 * \note : Update the '_state' attribute.
108 * Typically called by 'this->_inGate' when 'this->_inGate' is ready.
110 * Called by InGate::exNotifyFromPrecursor
112 void Node::exUpdateState()
114 if(_state==YACS::DISABLED)return;
115 if(_inGate.exIsReady())
116 setState(YACS::TOACTIVATE);
119 //! Notify this node that its execution has failed
121 * The node goes in FAILED state and
122 * propagate the notification through the outGate port
125 void Node::exFailedState()
127 DEBTRACE( "Node::exFailedState: " << getName() );
128 setState(YACS::FAILED);
129 _outGate.exNotifyFailed();
132 //! Notify this node that it has been disabled
134 * The node goes in DISABLED state and
135 * propagate the notification through the outGate port
138 void Node::exDisabledState()
140 DEBTRACE( "Node::exDisabledState: " << getName() );
141 setState(YACS::DISABLED);
142 _outGate.exNotifyDisabled();
145 InPort *Node::getInPort(const std::string& name) const throw(Exception)
150 ret=getInputPort(name);
154 ret=getInputDataStreamPort(name);
160 * \note: Contrary to getOutputPort method, this method returns the output port at highest level, possible.
161 * That is to say in some ComposedNode, like ForEachLoop or Switch, an outport inside 'this' is seen differently than the true outport.
163 OutPort *Node::getOutPort(const std::string& name) const throw(Exception)
168 ret=getOutputPort(name);
172 ret=getOutputDataStreamPort(name);
177 std::list<InPort *> Node::getSetOfInPort() const
180 list<InputPort *> data=getSetOfInputPort();
181 ret.insert(ret.end(),data.begin(),data.end());
182 list<InputDataStreamPort *> ds=getSetOfInputDataStreamPort();
183 ret.insert(ret.end(),ds.begin(),ds.end());
187 std::list<OutPort *> Node::getSetOfOutPort() const
190 list<OutputPort *> data=getSetOfOutputPort();
191 ret.insert(ret.end(),data.begin(),data.end());
192 list<OutputDataStreamPort *> ds=getSetOfOutputDataStreamPort();
193 ret.insert(ret.end(),ds.begin(),ds.end());
198 * gets a set of the composed nodes that constitute the ascendancy of this node, starting from root
199 * or from a particular ancestor
200 * \b WARNING : returned set is not sorted !
201 * @param levelToStop composed node which is the oldest ancestor required
202 * @return ascendancy, direct father first in set.
205 std::list<ComposedNode *> Node::getAllAscendanceOf(ComposedNode *levelToStop) const
207 list<ComposedNode *> ret;
208 if(this==levelToStop)
210 for(ComposedNode *iter=_father;iter!=levelToStop && iter!=0; iter=iter->_father)
215 bool Node::operator>(const Node& other) const
217 const ComposedNode *iter=other._father;
218 while(iter!=0 && iter!=this)
223 bool Node::operator<(const Node& other) const
225 const ComposedNode *iter=_father;
226 while(iter!=0 && iter!=(&other))
228 return iter==(&other);
232 * @return Implementation of node: C++, Python, CORBA...
233 * _implementation is set by a derived class in a Runtime
234 * it normally applies only to elementaryNodes and it is used by Ports to select Data Converters.
235 * Potential problem with Ports attached to composed Nodes...
238 string Node::getImplementation() const
240 return _implementation;
243 //! Becomes deprecated soon. Replaced by ComposedNode::CheckConsistency.
244 set<InputPort *> Node::edGetSetOfUnitializedInputPort() const
246 set<InputPort *> setOfUnitializedInputPort;
247 list<InputPort *> allOfInputPorts=getSetOfInputPort();
248 for(list<InputPort *>::const_iterator iter=allOfInputPorts.begin();iter!=allOfInputPorts.end();iter++)
250 if ( ! (*iter)->edIsInitialized() )
251 setOfUnitializedInputPort.insert(*iter);
253 return setOfUnitializedInputPort;
256 //! Becomes deprecated soon. Replaced by ComposedNode::CheckConsistency.
257 bool Node::edAreAllInputPortInitialized() const
259 set<InputPort *> setOfUnitializedInputPort = edGetSetOfUnitializedInputPort();
260 return ( setOfUnitializedInputPort.size() == 0);
264 * Called typically by Bloc to notify failure on potentially next nodes on the same scope of 'this'
266 void Node::exForwardFailed()
268 _outGate.exNotifyFailed();
272 * Called typically by Bloc to activate potentially next nodes on the same scope of 'this'
274 void Node::exForwardFinished()
276 _outGate.exNotifyDone();
280 * Called typically by ComposedNode to correctly update DF/CF/DS links
282 void Node::edDisconnectAllLinksWithMe()
284 _inGate.edDisconnectAllLinksToMe();
285 _outGate.edDisconnectAllLinksFromMe();
288 ComposedNode *Node::getRootNode() const throw(Exception)
291 throw Exception("No root node");
292 ComposedNode *iter=_father;
295 return (ComposedNode *)iter;
299 * checks validity of ports name, that must not contain a particular character '?'
300 * USAGE NOT CLEAR, not used so far, when are those characters set ?
303 void Node::checkValidityOfPortName(const std::string& name) throw(Exception)
305 if(name.find(SEP_CHAR_IN_PORT, 0 )!=string::npos)
307 string what("Port name "); what+=name; what+="not valid because it contains character "; what+=SEP_CHAR_IN_PORT;
308 throw Exception(what);
313 * @note : Check that 'node1' and 'node2' have exactly the same father
314 * @exception : If 'node1' and 'node2' have NOT exactly the same father
316 ComposedNode *Node::checkHavingCommonFather(Node *node1, Node *node2) throw(Exception)
318 if(node1!=0 && node2!=0)
320 if(node1->_father==node2->_father)
321 return node1->_father;
323 throw Exception("check failed : nodes have not the same father");
326 const std::string Node::getId() const
328 std::string id=getRootNode()->getName();
329 if(getRootNode() != this)
330 id= id+'.'+ getRootNode()->getChildName(this);
331 string::size_type debut =id.find_first_of('.');
332 while(debut != std::string::npos){
334 debut=id.find_first_of('.',debut);
339 void Node::setProperty(const std::string& name, const std::string& value)
341 _propertyMap[name]=value;
344 //! Return the node state in the context of its father
346 * \return the effective node state
348 * The node state is stored in a private attribute _state.
349 * This state is relative to its father state : a node with a
350 * TOACTIVATE state with a father node in a READY state is not
351 * to activate. Its effective state is only READY.
352 * This method returns the effective state of the node taking
353 * into account that of its father.
355 YACS::StatesForNode Node::getEffectiveState() const
357 if(!_father) //the root node
359 if(_state==YACS::DISABLED)
360 return YACS::DISABLED;
361 return _father->getEffectiveState(this);
364 //! Return the effective state of a node in the context of this one (its father)
366 * \param node: the node which effective state is queried
367 * \return the effective node state
369 YACS::StatesForNode Node::getEffectiveState(const Node* node) const
371 if(node->getState()==YACS::DISABLED)
372 return YACS::DISABLED;
374 YACS::StatesForNode effectiveState=getEffectiveState();
375 switch(effectiveState)
379 case YACS::TOACTIVATE:
382 return YACS::DISABLED;
386 return node->getState();
390 //! Return the color associated to a state
392 * \param state : the node state
393 * \return the associated color
395 std::string Node::getColorState(YACS::StatesForNode state) const
405 case YACS::TOACTIVATE:
407 case YACS::ACTIVATED:
424 //! Dump to the input stream a dot representation of the node
426 * \param os : the input stream
428 void Node::writeDot(std::ostream &os) const
430 os << getId() << "[fillcolor=\"" ;
431 YACS::StatesForNode state=getEffectiveState();
432 os << getColorState(state);
433 os << "\" label=\"" << getImplementation() << "Node:" ;
434 os << getQualifiedName() <<"\"];\n";
437 //! same as Node::getName() in most cases, but differs for children of switch
439 * used by writeDot to distinguish children of switch, by adding a prefix to the name.
440 * prefix is built on case id.
443 std::string Node::getQualifiedName() const
446 return _father->getMyQualifiedName(this);
450 //! return node instance identifiant, unique for each node instance
452 * node instance identifiant is used to check if to nodes pointers refers to the same instance
459 //! Sets the given state for node.
460 /*! It is strongly recommended to use this function if you want to
461 * change the state of the node, instead of direct access to _state field (_state = ...).
463 void Node::setState(YACS::StatesForNode theState)
465 DEBTRACE("Node::setState: " << getName() << " " << theState);
467 // emit notification to all observers registered with the dispatcher on any change of the node's state
471 //! emit notification to all observers registered with the dispatcher
473 * The dispatcher is unique and can be obtained by getDispatcher()
475 void Node::sendEvent(const std::string& event)
477 DEBTRACE("Node::sendEvent " << event);
478 Dispatcher* disp=Dispatcher::getDispatcher();
479 disp->dispatch(this,event);
483 * For use only when loading a previously saved execution
486 void YACS::ENGINE::StateLoader(Node* node, YACS::StatesForNode state)
488 node->setState(state);
491 //! indicates if the node is valid (returns 1) or not (returns 0)
493 * This method is useful when editing a schema. It has no meaning in execution.
494 * When a node is edited, its modified method must be called so when isValid is called, its state
495 * is updated (call to edUpdateState) before returning the validity check
501 if(_state > YACS::INVALID)
507 //! update the status of the node
509 * Only useful when editing a schema
510 * Do nothing in base Node : to implement in derived classes
512 void Node::edUpdateState()
514 DEBTRACE("Node::edUpdateState(): " << _modified);
518 //! returns a string that contains an error report if the node is in error
522 std::string Node::getErrorReport()
524 if(getState()==YACS::DISABLED)
525 return "<error node= "+getName()+ "state= DISABLED/>\n";
527 YACS::StatesForNode effectiveState=getEffectiveState();
529 DEBTRACE("Node::getErrorReport: " << getName() << " " << effectiveState << " " << _errorDetails);
530 if(effectiveState == YACS::READY || effectiveState == YACS::DONE)
533 std::string report="<error node= " ;
534 report=report + getName() ;
535 switch(effectiveState)
538 report=report+" state= INVALID";
541 report=report+" state= ERROR";
544 report=report+" state= FAILED";
549 report=report + ">\n" ;
550 report=report+_errorDetails;
551 report=report+"\n</error>";
555 //! returns a string that contains the name of the container log file if it exists
557 * Do nothing here. To subclass
559 std::string Node::getContainerLog()
564 //! Sets Node in modified state and its father if it exists
568 void Node::modified()
570 DEBTRACE("Node::modified() " << getName());
576 //! Put this node into TOLOAD state when possible
580 void Node::ensureLoading()
582 if(_state == YACS::READY)
583 setState(YACS::TOLOAD);