]> SALOME platform Git repositories - modules/yacs.git/blob - src/engine/Node.cxx
Salome HOME
copy tag mergefrom_BR_V0_1_CC_Salome_04oct07
[modules/yacs.git] / src / engine / Node.cxx
1 #include "Node.hxx"
2 #include "InputPort.hxx"
3 #include "OutputPort.hxx"
4 #include "ComposedNode.hxx"
5 #include "Dispatcher.hxx"
6 #include "InputDataStreamPort.hxx"
7 #include "OutputDataStreamPort.hxx"
8 #include <iostream>
9
10 //#define _DEVDEBUG_
11 #include "YacsTrace.hxx"
12
13 using namespace YACS::ENGINE;
14 using namespace std;
15
16 const char Node::SEP_CHAR_IN_PORT[]=".";
17
18 int Node::_total = 0;
19 std::map<int,Node*> Node::idMap;
20
21 Node::Node(const std::string& name):_name(name),_inGate(this),_outGate(this),_father(0),_state(YACS::INITED),
22                                     _implementation(Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME)
23 {
24   // Should be protected by lock ??
25   _numId = _total++;
26   idMap[_numId]=this;
27 }
28
29 Node::Node(const Node& other, ComposedNode *father):_inGate(this),_outGate(this),_name(other._name),_father(father),
30                                                    _state(YACS::INITED),_implementation(other._implementation),
31                                                     _propertyMap(other._propertyMap)
32 {
33   _numId = _total++;
34   idMap[_numId]=this;
35 }
36
37 Node::~Node()
38 {
39 }
40
41 /**
42  *  initialisation of all input and output ports and gates, for execution
43  */
44
45 void Node::init(bool start)
46 {
47   _inGate.exReset();
48   _outGate.exReset();
49   if(_state == YACS::DISABLED)
50     {
51       exDisabledState(); // to refresh propagation of DISABLED state 
52       return;
53     }
54   setState(YACS::INITED);
55 }
56
57 Node *Node::clone(ComposedNode *father, bool editionOnly) const
58 {
59   Node *ret=simpleClone(father,editionOnly);
60   ret->performDuplicationOfPlacement(*this);
61   return ret;
62 }
63
64 /**
65  *  get the set of all nodes connected to the outGate
66  */
67
68 set<Node *> Node::getOutNodes() const
69 {
70   set<Node *> ret;
71   set<InGate *> inGates=_outGate.edSetInGate();
72   for(set<InGate *>::iterator iter=inGates.begin();iter!=inGates.end();iter++)
73     ret.insert((*iter)->getNode());
74   return ret;
75 }
76
77 bool Node::exIsControlReady() const
78 {
79   return _inGate.exIsReady();
80 }
81
82 /*!
83  * \note : Update the '_state' attribute.
84  *          Typically called by 'this->_inGate' when 'this->_inGate' is ready.
85  *
86  *          Called by InGate::exNotifyFromPrecursor 
87  */
88
89 void Node::exUpdateState()
90 {
91   if(_state==YACS::DISABLED)return;
92   if(_inGate.exIsReady())
93     setState(YACS::TOACTIVATE);
94 }
95
96 //! Notify this node that its execution has failed
97 /*!
98  * The node goes in FAILED state and 
99  * propagate the notification through the outGate port
100  *
101  */
102 void Node::exFailedState()
103 {
104   DEBTRACE( "Node::exFailedState: " << getName() );
105   setState(YACS::FAILED);
106   _outGate.exNotifyFailed();
107 }
108
109 //! Notify this node that it has been disabled
110 /*!
111  * The node goes in DISABLED state and
112  * propagate the notification through the outGate port
113  *
114  */
115 void Node::exDisabledState()
116 {
117   DEBTRACE( "Node::exDisabledState: " << getName() );
118   setState(YACS::DISABLED);
119   _outGate.exNotifyDisabled();
120 }
121
122 InPort *Node::getInPort(const std::string& name) const throw(Exception)
123 {
124   InPort *ret;
125   try
126     {
127       ret=getInputPort(name);
128     }
129   catch(Exception& e)
130     {
131       ret=getInputDataStreamPort(name);
132     }
133   return ret;
134 }
135
136 /*!
137  * \note: Contrary to getOutputPort method, this method returns the output port at highest level, possible.
138  *        That is to say in some ComposedNode, like ForEachLoop or Switch, an outport inside 'this' is seen differently than the true outport.
139  */
140 OutPort *Node::getOutPort(const std::string& name) const throw(Exception)
141 {
142   OutPort *ret;
143   try
144     {
145       ret=getOutputPort(name);
146     }
147   catch(Exception& e)
148     {
149       ret=getOutputDataStreamPort(name);
150     }
151   return ret;
152 }
153
154 std::list<InPort *> Node::getSetOfInPort() const
155 {
156   list<InPort *> ret;
157   list<InputPort *> data=getSetOfInputPort();
158   ret.insert(ret.end(),data.begin(),data.end());
159   list<InputDataStreamPort *> ds=getSetOfInputDataStreamPort();
160   ret.insert(ret.end(),ds.begin(),ds.end());
161   return ret;
162 }
163
164 std::list<OutPort *> Node::getSetOfOutPort() const
165 {
166   list<OutPort *> ret;
167   list<OutputPort *> data=getSetOfOutputPort();
168   ret.insert(ret.end(),data.begin(),data.end());
169   list<OutputDataStreamPort *> ds=getSetOfOutputDataStreamPort();
170   ret.insert(ret.end(),ds.begin(),ds.end());
171   return ret;
172 }
173
174 /**
175  * gets a set of the composed nodes that constitute the ascendancy of this node, starting from root
176  * or from a particular ancestor
177  * \b WARNING : returned set is not sorted !
178  * @param  levelToStop   composed node which is the oldest ancestor required
179  * @return               ascendancy, direct father first in set.
180  */
181
182 std::set<ComposedNode *> Node::getAllAscendanceOf(ComposedNode *levelToStop)
183 {
184   set<ComposedNode *> ret;
185   if(this==levelToStop)
186     return ret;
187   for(ComposedNode *iter=_father;iter!=levelToStop && iter!=0; iter=iter->_father)
188       ret.insert(iter);
189   return ret;
190 }
191
192 /**
193  *  @return Implementation of node: C++, Python, CORBA...
194  *  _implementation is set by a derived class in a Runtime
195  *  it normally applies only to elementaryNodes and it is used by Ports to select Data Converters.
196  *  Potential problem with Ports attached to composed Nodes...
197  */
198
199 string Node::getImplementation()
200 {
201   return _implementation;
202 }
203
204 //! Becomes deprecated soon. Replaced by ComposedNode::CheckConsistency.
205 set<InputPort *> Node::edGetSetOfUnitializedInputPort() const
206 {
207   set<InputPort *> setOfUnitializedInputPort;
208   list<InputPort *> allOfInputPorts=getSetOfInputPort();
209   for(list<InputPort *>::const_iterator iter=allOfInputPorts.begin();iter!=allOfInputPorts.end();iter++)
210     {
211       if ( ! (*iter)->edIsInitialized() )
212         setOfUnitializedInputPort.insert(*iter);
213     }
214   return setOfUnitializedInputPort;
215 }
216
217 //! Becomes deprecated soon. Replaced by ComposedNode::CheckConsistency.
218 bool Node::edAreAllInputPortInitialized() const
219 {
220   set<InputPort *> setOfUnitializedInputPort = edGetSetOfUnitializedInputPort();
221   return ( setOfUnitializedInputPort.size() == 0);
222 }
223
224 /*!
225  * Called typically by Bloc to notify failure on potentially next nodes on the same scope of 'this'
226  */
227 void Node::exForwardFailed()
228 {
229   _outGate.exNotifyFailed();
230 }
231
232 /*!
233  * Called typically by Bloc to activate potentially next nodes on the same scope of 'this'
234  */
235 void Node::exForwardFinished()
236 {
237   _outGate.exNotifyDone();
238 }
239
240 /*!
241  * Called typically by ComposedNode to correctly update DF/CF/DS links
242  */
243 void Node::edDisconnectAllLinksWithMe()
244 {
245   _inGate.edDisconnectAllLinksToMe();
246   _outGate.edDisconnectAllLinksFromMe();
247 }
248
249 ComposedNode *Node::getRootNode() throw(Exception)
250 {
251   if(!_father)
252     throw Exception("No root node");
253   ComposedNode *iter=_father;
254   while(iter->_father)
255     iter=iter->_father;
256   return iter;
257 }
258
259 /**
260  * checks validity of ports name, that must not contain a particular character '?'
261  * USAGE NOT CLEAR, not used so far, when are those characters set ?
262  */
263
264 void Node::checkValidityOfPortName(const std::string& name) throw(Exception)
265 {
266   if(name.find(SEP_CHAR_IN_PORT, 0 )!=string::npos)
267     {
268       string what("Port name "); what+=name; what+="not valid because it contains character "; what+=SEP_CHAR_IN_PORT;
269       throw Exception(what);
270     }
271 }
272
273 /**
274  * @note : Check that 'node1' and 'node2' have exactly the same father
275  * @exception : If 'node1' and 'node2' have NOT exactly the same father
276  */
277 ComposedNode *Node::checkHavingCommonFather(Node *node1, Node *node2) throw(Exception)
278 {
279   if(node1!=0 && node2!=0)
280     {
281       if(node1->_father==node2->_father)
282         return node1->_father;
283     }
284   throw Exception("check failed : nodes have not the same father");
285 }
286
287 const std::string Node::getId()
288 {
289     std::string id=getRootNode()->getName();
290     if(getRootNode() != this)
291       id= id+'.'+ getRootNode()->getChildName(this);
292     string::size_type debut =id.find_first_of('.');
293     while(debut != std::string::npos){
294         id[debut]='_';
295         debut=id.find_first_of('.',debut);
296     }
297     return id;
298 }
299
300 void Node::setProperty(const std::string& name, const std::string& value)
301 {
302     _propertyMap[name]=value;
303 }
304
305 //! Return the node state in the context of its father
306 /*!
307  * \return the effective node state
308  *
309  * The node state is stored in a private attribute _state.
310  * This state is relative to its father state : a node with a
311  * TOACTIVATE state with a father node in a INITED state is not
312  * to activate. Its effective state is only INITED.
313  * This method returns the effective state of the node taking
314  * into account that of its father.
315  */
316 YACS::StatesForNode Node::getEffectiveState()
317 {
318   if(!_father)   //the root node
319     return _state;
320   if(_state==YACS::DISABLED)
321     return YACS::DISABLED;
322   return _father->getEffectiveState(this);
323 }
324
325 //! Return the effective state of a node in the context of this one (its father)
326 /*!
327  * \param node: the node which effective state is queried
328  * \return the effective node state
329  */
330 YACS::StatesForNode Node::getEffectiveState(Node* node)
331 {
332   if(node->getState()==YACS::DISABLED)
333     return YACS::DISABLED;
334
335   YACS::StatesForNode effectiveState=getEffectiveState();
336   switch(effectiveState)
337     {
338     case YACS::INITED:
339       return YACS::INITED;
340     case YACS::TOACTIVATE:
341       return YACS::INITED;
342     case YACS::DISABLED:
343       return YACS::DISABLED;
344     case YACS::ERROR:
345       return YACS::FAILED;
346     default:
347       return node->getState();
348     }
349 }
350
351 //! Return the color associated to a state
352 /*!
353  * \param state : the node state
354  * \return the associated color
355  */
356 std::string Node::getColorState(YACS::StatesForNode state)
357 {
358   switch(state)
359     {
360     case YACS::INITED:
361       return "pink";
362     case YACS::TOLOAD:
363       return "magenta";
364     case YACS::LOADED:
365       return "magenta";
366     case YACS::TOACTIVATE:
367       return "purple";
368     case YACS::ACTIVATED:
369       return "blue";
370     case YACS::DONE:
371       return "green";
372     case YACS::ERROR:
373       return "red";
374     case YACS::FAILED:
375       return "orange";
376     case YACS::DISABLED:
377       return "grey";
378     case YACS::PAUSE:
379       return "white";
380     default:
381       return "white";
382     }
383 }
384
385 //! Dump to the input stream a dot representation of the node
386 /*!
387  *  \param os : the input stream
388  */
389 void Node::writeDot(std::ostream &os)
390 {
391   os << getId() << "[fillcolor=\"" ;
392   YACS::StatesForNode state=getEffectiveState();
393   os << getColorState(state);
394   os << "\" label=\"" << getImplementation() << "Node:" ;
395   os << getQualifiedName() <<"\"];\n";
396 }
397
398 //! same as Node::getName() in most cases, but differs for children of switch
399 /*!
400  *  used by writeDot to distinguish children of switch, by adding a prefix to the name.
401  *  prefix is built on case id.
402  */
403
404 std::string Node::getQualifiedName() const
405 {
406   if(_father)
407     return _father->getMyQualifiedName(this);
408   return getName();
409 }
410
411 //! return node instance identifiant, unique for each node instance 
412 /*!
413  * node instance identifiant is used to check if to nodes pointers refers to the same instance
414  */ 
415 int Node::getNumId()
416 {
417   return _numId;
418 }
419
420 //! Sets the given state for node.
421 /*! It is strongly recommended to use this function if you want to
422  *  change the state of the node, instead of direct access to _state field (_state = ...).
423  */
424 void Node::setState(YACS::StatesForNode theState)
425 {
426   _state = theState;
427   // emit notification to all observers registered with the dispatcher on any change of the node's state
428   sendEvent("status");
429 }
430
431 //! emit notification to all observers registered with  the dispatcher 
432 /*!
433  * The dispatcher is unique and can be obtained by getDispatcher()
434  */
435 void Node::sendEvent(const std::string& event)
436 {
437   Dispatcher* disp=Dispatcher::getDispatcher();
438   disp->dispatch(this,event);
439 }
440
441 /*!
442  *  For use only when loading a previously saved execution
443  */
444
445 void YACS::ENGINE::StateLoader(Node* node, YACS::StatesForNode state)
446 {
447   node->setState(state);
448 }