#include "InputPort.hxx"
#include "OutputPort.hxx"
#include "ComposedNode.hxx"
+#include "Dispatcher.hxx"
#include "InputDataStreamPort.hxx"
#include "OutputDataStreamPort.hxx"
+#include <iostream>
+
+//#define _DEVDEBUG_
+#include "YacsTrace.hxx"
using namespace YACS::ENGINE;
using namespace std;
-Node::Node(const string& name):_name(name),_inGate(this),_outGate(this),_father(0),_colour(YACS::White),_state(YACS::INITED)
+const char Node::SEP_CHAR_IN_PORT[]=".";
+
+int Node::_total = 0;
+std::map<int,Node*> Node::idMap;
+
+Node::Node(const std::string& name):_name(name),_inGate(this),_outGate(this),_father(0),_state(YACS::INITED),
+ _implementation(Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME)
{
+ // Should be protected by lock ??
+ _numId = _total++;
+ idMap[_numId]=this;
+}
+
+Node::Node(const Node& other, ComposedNode *father):_inGate(this),_outGate(this),_name(other._name),_father(father),
+ _state(YACS::INITED),_implementation(other._implementation),
+ _propertyMap(other._propertyMap)
+{
+ _numId = _total++;
+ idMap[_numId]=this;
}
Node::~Node()
* initialisation of all input and output ports and gates, for execution
*/
-void Node::init()
+void Node::init(bool start)
{
_inGate.exReset();
- for(set<OutputPort *>::iterator iter=_setOfOutputPort.begin();iter!=_setOfOutputPort.end();iter++)
- (*iter)->exInit();
- for(set<InputPort *>::iterator iter2=_setOfInputPort.begin();iter2!=_setOfInputPort.end();iter2++)
- (*iter2)->exInit();
- if(_inGate.exIsReady())
- _state=YACS::TOACTIVATE;
- else
- _state=YACS::INITED;
+ _outGate.exReset();
+ if(_state == YACS::DISABLED)
+ {
+ exDisabledState(); // to refresh propagation of DISABLED state
+ return;
+ }
+ setState(YACS::INITED);
+}
+
+Node *Node::clone(ComposedNode *father, bool editionOnly) const
+{
+ Node *ret=simpleClone(father,editionOnly);
+ ret->performDuplicationOfPlacement(*this);
+ return ret;
}
/**
return ret;
}
-/**
- * @note : Update the '_state' attribute.
+bool Node::exIsControlReady() const
+{
+ return _inGate.exIsReady();
+}
+
+/*!
+ * \note : Update the '_state' attribute.
* Typically called by 'this->_inGate' when 'this->_inGate' is ready.
+ *
+ * Called by InGate::exNotifyFromPrecursor
*/
void Node::exUpdateState()
{
+ if(_state==YACS::DISABLED)return;
if(_inGate.exIsReady())
- if(areAllInputPortsValid())
- _state=YACS::TOACTIVATE;
- else
- {
- string what("Node::exUpdateState : Invalid graph given : Node with name \"");
- what+=_name; what+="\" ready to run whereas some inputports are not set correctly\nCheck coherence DF/CF";
- throw Exception(what);
- }
+ setState(YACS::TOACTIVATE);
}
-int Node::getNumberOfInputPorts() const
+//! Notify this node that its execution has failed
+/*!
+ * The node goes in FAILED state and
+ * propagate the notification through the outGate port
+ *
+ */
+void Node::exFailedState()
{
- return _setOfInputPort.size();
+ DEBTRACE( "Node::exFailedState: " << getName() );
+ setState(YACS::FAILED);
+ _outGate.exNotifyFailed();
}
-int Node::getNumberOfOutputPorts() const
+//! Notify this node that it has been disabled
+/*!
+ * The node goes in DISABLED state and
+ * propagate the notification through the outGate port
+ *
+ */
+void Node::exDisabledState()
{
- return _setOfOutputPort.size();
+ DEBTRACE( "Node::exDisabledState: " << getName() );
+ setState(YACS::DISABLED);
+ _outGate.exNotifyDisabled();
}
-InputPort *Node::getInputPort(const string& name) const throw(Exception)
+InPort *Node::getInPort(const std::string& name) const throw(Exception)
{
- return getPort<InputPort>(name,_setOfInputPort);
+ InPort *ret;
+ try
+ {
+ ret=getInputPort(name);
+ }
+ catch(Exception& e)
+ {
+ ret=getInputDataStreamPort(name);
+ }
+ return ret;
}
-OutputPort *Node::getOutputPort(const string& name) const throw(Exception)
+/*!
+ * \note: Contrary to getOutputPort method, this method returns the output port at highest level, possible.
+ * That is to say in some ComposedNode, like ForEachLoop or Switch, an outport inside 'this' is seen differently than the true outport.
+ */
+OutPort *Node::getOutPort(const std::string& name) const throw(Exception)
{
- return getPort<OutputPort>(name,_setOfOutputPort);
+ OutPort *ret;
+ try
+ {
+ ret=getOutputPort(name);
+ }
+ catch(Exception& e)
+ {
+ ret=getOutputDataStreamPort(name);
+ }
+ return ret;
}
-InputDataStreamPort *Node::getInputDataStreamPort(const string& name) const throw(Exception)
+std::list<InPort *> Node::getSetOfInPort() const
{
- return getPort<InputDataStreamPort>(name,_setOfInputDataStreamPort);
+ list<InPort *> ret;
+ list<InputPort *> data=getSetOfInputPort();
+ ret.insert(ret.end(),data.begin(),data.end());
+ list<InputDataStreamPort *> ds=getSetOfInputDataStreamPort();
+ ret.insert(ret.end(),ds.begin(),ds.end());
+ return ret;
}
-OutputDataStreamPort *Node::getOutputDataStreamPort(const string& name) const throw(Exception)
+std::list<OutPort *> Node::getSetOfOutPort() const
{
- return getPort<OutputDataStreamPort>(name,_setOfOutputDataStreamPort);
+ list<OutPort *> ret;
+ list<OutputPort *> data=getSetOfOutputPort();
+ ret.insert(ret.end(),data.begin(),data.end());
+ list<OutputDataStreamPort *> ds=getSetOfOutputDataStreamPort();
+ ret.insert(ret.end(),ds.begin(),ds.end());
+ return ret;
}
-
/**
* gets a set of the composed nodes that constitute the ascendancy of this node, starting from root
* or from a particular ancestor
+ * \b WARNING : returned set is not sorted !
* @param levelToStop composed node which is the oldest ancestor required
* @return ascendancy, direct father first in set.
*/
-set<ComposedNode *> Node::getAllAscendanceOf(ComposedNode *levelToStop)
+std::set<ComposedNode *> Node::getAllAscendanceOf(ComposedNode *levelToStop)
{
set<ComposedNode *> ret;
+ if(this==levelToStop)
+ return ret;
for(ComposedNode *iter=_father;iter!=levelToStop && iter!=0; iter=iter->_father)
ret.insert(iter);
return ret;
return _implementation;
}
-/**
- * checks if all input ports contains a valid data. Used at execution to change the state of the node
- * for activation.
- */
-
-bool Node::areAllInputPortsValid() const
+//! Becomes deprecated soon. Replaced by ComposedNode::CheckConsistency.
+set<InputPort *> Node::edGetSetOfUnitializedInputPort() const
{
- bool ret=true;
- for(set<InputPort *>::const_iterator iter=_setOfInputPort.begin();iter!=_setOfInputPort.end();iter++)
+ set<InputPort *> setOfUnitializedInputPort;
+ list<InputPort *> allOfInputPorts=getSetOfInputPort();
+ for(list<InputPort *>::const_iterator iter=allOfInputPorts.begin();iter!=allOfInputPorts.end();iter++)
{
- ret=!(*iter)->isEmpty();
- if (!ret) break;
+ if ( ! (*iter)->edIsInitialized() )
+ setOfUnitializedInputPort.insert(*iter);
}
- return ret;
+ return setOfUnitializedInputPort;
+}
+
+//! Becomes deprecated soon. Replaced by ComposedNode::CheckConsistency.
+bool Node::edAreAllInputPortInitialized() const
+{
+ set<InputPort *> setOfUnitializedInputPort = edGetSetOfUnitializedInputPort();
+ return ( setOfUnitializedInputPort.size() == 0);
+}
+
+/*!
+ * Called typically by Bloc to notify failure on potentially next nodes on the same scope of 'this'
+ */
+void Node::exForwardFailed()
+{
+ _outGate.exNotifyFailed();
+}
+
+/*!
+ * Called typically by Bloc to activate potentially next nodes on the same scope of 'this'
+ */
+void Node::exForwardFinished()
+{
+ _outGate.exNotifyDone();
+}
+
+/*!
+ * Called typically by ComposedNode to correctly update DF/CF/DS links
+ */
+void Node::edDisconnectAllLinksWithMe()
+{
+ _inGate.edDisconnectAllLinksToMe();
+ _outGate.edDisconnectAllLinksFromMe();
}
ComposedNode *Node::getRootNode() throw(Exception)
* USAGE NOT CLEAR, not used so far, when are those characters set ?
*/
-void Node::checkValidityOfPortName(const string& name) throw(Exception)
+void Node::checkValidityOfPortName(const std::string& name) throw(Exception)
{
if(name.find(SEP_CHAR_IN_PORT, 0 )!=string::npos)
{
if(node1!=0 && node2!=0)
{
if(node1->_father==node2->_father)
- return node1->_father;
+ return node1->_father;
}
throw Exception("check failed : nodes have not the same father");
}
-/**
- * set color for inGates : display
- * USAGE NOT CLEAR, not used so far
+const std::string Node::getId()
+{
+ std::string id=getRootNode()->getName();
+ if(getRootNode() != this)
+ id= id+'.'+ getRootNode()->getChildName(this);
+ string::size_type debut =id.find_first_of('.');
+ while(debut != std::string::npos){
+ id[debut]='_';
+ debut=id.find_first_of('.',debut);
+ }
+ return id;
+}
+
+void Node::setProperty(const std::string& name, const std::string& value)
+{
+ _propertyMap[name]=value;
+}
+
+//! Return the node state in the context of its father
+/*!
+ * \return the effective node state
+ *
+ * The node state is stored in a private attribute _state.
+ * This state is relative to its father state : a node with a
+ * TOACTIVATE state with a father node in a INITED state is not
+ * to activate. Its effective state is only INITED.
+ * This method returns the effective state of the node taking
+ * into account that of its father.
*/
+YACS::StatesForNode Node::getEffectiveState()
+{
+ if(!_father) //the root node
+ return _state;
+ if(_state==YACS::DISABLED)
+ return YACS::DISABLED;
+ return _father->getEffectiveState(this);
+}
-void Node::initForDFS() const
+//! Return the effective state of a node in the context of this one (its father)
+/*!
+ * \param node: the node which effective state is queried
+ * \return the effective node state
+ */
+YACS::StatesForNode Node::getEffectiveState(Node* node)
{
- _colour=YACS::White;
- set<InGate *> inGates=_outGate.edSetInGate();
- for(set<InGate *>::iterator iter=inGates.begin();iter!=inGates.end();iter++)
- (*iter)->initForDFS();
+ if(node->getState()==YACS::DISABLED)
+ return YACS::DISABLED;
+
+ YACS::StatesForNode effectiveState=getEffectiveState();
+ switch(effectiveState)
+ {
+ case YACS::INITED:
+ return YACS::INITED;
+ case YACS::TOACTIVATE:
+ return YACS::INITED;
+ case YACS::DISABLED:
+ return YACS::DISABLED;
+ case YACS::ERROR:
+ return YACS::FAILED;
+ default:
+ return node->getState();
+ }
+}
+
+//! Return the color associated to a state
+/*!
+ * \param state : the node state
+ * \return the associated color
+ */
+std::string Node::getColorState(YACS::StatesForNode state)
+{
+ switch(state)
+ {
+ case YACS::INITED:
+ return "pink";
+ case YACS::TOLOAD:
+ return "magenta";
+ case YACS::LOADED:
+ return "magenta";
+ case YACS::TOACTIVATE:
+ return "purple";
+ case YACS::ACTIVATED:
+ return "blue";
+ case YACS::DONE:
+ return "green";
+ case YACS::ERROR:
+ return "red";
+ case YACS::FAILED:
+ return "orange";
+ case YACS::DISABLED:
+ return "grey";
+ case YACS::PAUSE:
+ return "white";
+ default:
+ return "white";
+ }
+}
+
+//! Dump to the input stream a dot representation of the node
+/*!
+ * \param os : the input stream
+ */
+void Node::writeDot(std::ostream &os)
+{
+ os << getId() << "[fillcolor=\"" ;
+ YACS::StatesForNode state=getEffectiveState();
+ os << getColorState(state);
+ os << "\" label=\"" << getImplementation() << "Node:" ;
+ os << getQualifiedName() <<"\"];\n";
+}
+
+//! same as Node::getName() in most cases, but differs for children of switch
+/*!
+ * used by writeDot to distinguish children of switch, by adding a prefix to the name.
+ * prefix is built on case id.
+ */
+
+std::string Node::getQualifiedName() const
+{
+ if(_father)
+ return _father->getMyQualifiedName(this);
+ return getName();
+}
+
+//! return node instance identifiant, unique for each node instance
+/*!
+ * node instance identifiant is used to check if to nodes pointers refers to the same instance
+ */
+int Node::getNumId()
+{
+ return _numId;
+}
+
+//! Sets the given state for node.
+/*! It is strongly recommended to use this function if you want to
+ * change the state of the node, instead of direct access to _state field (_state = ...).
+ */
+void Node::setState(YACS::StatesForNode theState)
+{
+ _state = theState;
+ // emit notification to all observers registered with the dispatcher on any change of the node's state
+ sendEvent("status");
+}
+
+//! emit notification to all observers registered with the dispatcher
+/*!
+ * The dispatcher is unique and can be obtained by getDispatcher()
+ */
+void Node::sendEvent(const std::string& event)
+{
+ Dispatcher* disp=Dispatcher::getDispatcher();
+ disp->dispatch(this,event);
+}
+
+/*!
+ * For use only when loading a previously saved execution
+ */
+
+void YACS::ENGINE::StateLoader(Node* node, YACS::StatesForNode state)
+{
+ node->setState(state);
}