]> SALOME platform Git repositories - modules/yacs.git/blob - src/engine/Node.cxx
Salome HOME
[PY3] Fix appels à print dans les schéma xml et scripts python
[modules/yacs.git] / src / engine / Node.cxx
1 // Copyright (C) 2006-2016  CEA/DEN, EDF R&D
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "Node.hxx"
21 #include "DynParaLoop.hxx"
22 #include "InputPort.hxx"
23 #include "OutputPort.hxx"
24 #include "InPropertyPort.hxx"
25 #include "ComposedNode.hxx"
26 #include "Dispatcher.hxx"
27 #include "InputDataStreamPort.hxx"
28 #include "OutputDataStreamPort.hxx"
29 #include <iostream>
30
31 //#define _DEVDEBUG_
32 #include "YacsTrace.hxx"
33
34 using namespace YACS::ENGINE;
35 using namespace std;
36
37 /*! \class YACS::ENGINE::Node
38  *  \brief Base class for all nodes
39  *
40  * \ingroup Nodes
41  */
42
43 const char Node::SEP_CHAR_IN_PORT[]=".";
44
45 int Node::_total = 0;
46 std::map<int,Node*> Node::idMap;
47
48 NodeStateNameMap::NodeStateNameMap()
49 {
50   insert(make_pair(YACS::READY, "READY"));
51   insert(make_pair(YACS::TOLOAD, "TOLOAD"));
52   insert(make_pair(YACS::LOADED, "LOADED"));
53   insert(make_pair(YACS::TOACTIVATE, "TOACTIVATE"));
54   insert(make_pair(YACS::ACTIVATED, "ACTIVATED"));
55   insert(make_pair(YACS::DESACTIVATED, "DESACTIVATED"));
56   insert(make_pair(YACS::DONE, "DONE"));
57   insert(make_pair(YACS::SUSPENDED, "SUSPENDED"));
58   insert(make_pair(YACS::LOADFAILED, "LOADFAILED"));
59   insert(make_pair(YACS::EXECFAILED, "EXECFAILED"));
60   insert(make_pair(YACS::PAUSE, "PAUSE"));
61   insert(make_pair(YACS::INTERNALERR, "INTERNALERR"));
62   insert(make_pair(YACS::DISABLED, "DISABLED"));
63   insert(make_pair(YACS::FAILED, "FAILED"));
64   insert(make_pair(YACS::ERROR, "ERROR"));
65 }
66
67
68 Node::Node(const std::string& name):_name(name),_inGate(this),_outGate(this),_father(0),_state(YACS::READY),
69                                     _implementation(Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME),_modified(1)
70 {
71   // Should be protected by lock ??
72   _numId = _total++;
73   idMap[_numId]=this;
74
75   // Every node has an InPropertyPort
76   _inPropertyPort = new InPropertyPort("__InPropertyPort__Node__YACS_", this, Runtime::_tc_propvec);
77 }
78
79 Node::Node(const Node& other, ComposedNode *father):_inGate(this),_outGate(this),_name(other._name),_father(father),
80                                                    _state(YACS::READY),_implementation(other._implementation),
81                                                     _propertyMap(other._propertyMap),_modified(1)
82 {
83   _numId = _total++;
84   idMap[_numId]=this;
85
86   // Every node has an InPropertyPort
87   _inPropertyPort = new InPropertyPort("__InPropertyPort__Node__YACS_", this, Runtime::_tc_propvec);
88 }
89
90 Node::~Node()
91 {
92   delete _inPropertyPort;
93 }
94
95 /**
96  *  initialisation of all input and output ports and gates, for execution
97  */
98
99 void Node::init(bool start)
100 {
101   _inGate.exReset();
102   _outGate.exReset();
103   if(_state == YACS::DISABLED)
104     {
105       exDisabledState(); // to refresh propagation of DISABLED state 
106       return;
107     }
108   setState(YACS::READY);
109 }
110
111 /*!
112  * This method clones \a this by :
113  *
114  * - deep copying nodes, links, ports, types
115  * - containers are either deep copied or shallow copied depending on _isAttachedOnCloning attribute.
116  * - component are either deep copied or shallow copied depending on _isAttachedOnCloning attribute.
117  *
118  * So \b this \b method \b clone \b is \b dedicated \b for \b DynParaLoop \b class \b or \b subclasses.
119  * It \b should \b not \b be \b used \b elsewhere, because
120  * _isAttachedOnCloning attribute is an attribute in the engine not for GUI/TUI aspects.
121  * For GUI/TUI manipulation cloneWithoutCompAndContDeepCpy method should be used preferably.
122  *
123  * \param [in] father - The new father of the returned clone.
124  * \param [in] editionOnly ignored
125  *
126  * \sa cloneWithoutCompAndContDeepCpy
127  */
128 Node *Node::clone(ComposedNode *father, bool editionOnly) const
129 {
130   Node *ret(simpleClone(father,editionOnly));
131   ret->performDuplicationOfPlacement(*this);
132   return ret;
133 }
134
135 /*!
136  * This method clones \a this by :
137  * - deep copying nodes, links, ports, types
138  * - shallow copy containers
139  * - shallow copy components
140  *
141  * So this method simply ignores isAttachedOnCloning attribute for both containers and components.
142  * So this method is dedicated for the GUI/TUI users.
143  *
144  * \param [in] father - The new father of the returned clone.
145  * \param [in] editionOnly ignored
146  */
147 Node *Node::cloneWithoutCompAndContDeepCpy(ComposedNode *father, bool editionOnly) const
148 {
149   Node *ret(simpleClone(father,editionOnly));
150   ret->performShallowDuplicationOfPlacement(*this);
151   return ret;
152 }
153
154 //! Change the name of the node
155 /*!
156  *  raise an exception if the name is already used in the scope of its father 
157  *  \param name : the new name
158  */
159 void Node::setName(const std::string& name)
160 {
161   if(_father)
162     {
163       if(_father->isNameAlreadyUsed(name))
164         {
165           if ( _father->getChildByName(name) != this )
166             {
167               std::string what("Name "); 
168               what+=name;
169               what+=" already exists in the scope of "; what+=_father->getName();
170               throw Exception(what);
171             }
172         }
173     }
174   _name=name;
175 }
176
177 /**
178  *  get the set of all nodes connected to the outGate
179  */
180
181 list<Node *> Node::getOutNodes() const
182 {
183   list<Node *> ret;
184   list<InGate *> inGates=_outGate.edSetInGate();
185   for(list<InGate *>::iterator iter=inGates.begin();iter!=inGates.end();iter++)
186     ret.push_back((*iter)->getNode());
187   return ret;
188 }
189
190 bool Node::exIsControlReady() const
191 {
192   return _inGate.exIsReady();
193 }
194
195 //! Update the node state
196 /*!
197  * \note : Update the '_state' attribute.
198  *          Typically called by 'this->_inGate' when 'this->_inGate' is ready.
199  *
200  *          Called by InGate::exNotifyFromPrecursor 
201  */
202 void Node::exUpdateState()
203 {
204   if(_state==YACS::DISABLED)return;
205   if(_inGate.exIsReady())
206     setState(YACS::TOACTIVATE);
207 }
208
209 //! Notify this node that its execution has failed
210 /*!
211  * The node goes in FAILED state and 
212  * propagate the notification through the outGate port
213  *
214  */
215 void Node::exFailedState()
216 {
217   DEBTRACE( "Node::exFailedState: " << getName() );
218   setState(YACS::FAILED);
219   _outGate.exNotifyFailed();
220 }
221
222 //! Notify this node that it has been disabled
223 /*!
224  * The node goes in DISABLED state and
225  * propagate the notification through the outGate port
226  *
227  */
228 void Node::exDisabledState()
229 {
230   DEBTRACE( "Node::exDisabledState: " << getName() );
231   setState(YACS::DISABLED);
232   _outGate.exNotifyDisabled();
233 }
234
235 InPort *Node::getInPort(const std::string& name) const throw(YACS::Exception)
236 {
237   InPort *ret;
238   try
239     {
240       ret=getInputPort(name);
241     }
242   catch(Exception& e)
243     {
244       ret=getInputDataStreamPort(name);
245     }
246   return ret;
247 }
248
249 InPropertyPort *
250 Node::getInPropertyPort() const throw(YACS::Exception)
251 {
252   return _inPropertyPort;
253 }
254
255 InputPort *
256 Node::getInputPort(const std::string& name) const throw(YACS::Exception)
257 {
258   if (name == "__InPropertyPort__Node__YACS_")
259     return _inPropertyPort;
260   else
261   {
262     std::string what("Node::getInputPort : the port with name "); what+=name; what+=" does not exist on the current level";
263     throw Exception(what);
264   }
265 }
266
267 /*!
268  * \note: Contrary to getOutputPort method, this method returns the output port at highest level, possible.
269  *        That is to say in some ComposedNode, like ForEachLoop or Switch, an outport inside 'this' is seen differently than the true outport.
270  */
271 OutPort *Node::getOutPort(const std::string& name) const throw(YACS::Exception)
272 {
273   OutPort *ret;
274   try
275     {
276       ret=getOutputPort(name);
277     }
278   catch(Exception& e)
279     {
280       ret=getOutputDataStreamPort(name);
281     }
282   return ret;
283 }
284
285 std::list<InPort *> Node::getSetOfInPort() const
286 {
287   list<InPort *> ret;
288   list<InputPort *> data=getSetOfInputPort();
289   ret.insert(ret.end(),data.begin(),data.end());
290   list<InputDataStreamPort *> ds=getSetOfInputDataStreamPort();
291   ret.insert(ret.end(),ds.begin(),ds.end());
292   return ret;
293 }
294
295 std::list<OutPort *> Node::getSetOfOutPort() const
296 {
297   list<OutPort *> ret;
298   list<OutputPort *> data=getSetOfOutputPort();
299   ret.insert(ret.end(),data.begin(),data.end());
300   list<OutputDataStreamPort *> ds=getSetOfOutputDataStreamPort();
301   ret.insert(ret.end(),ds.begin(),ds.end());
302   return ret;
303 }
304
305 /**
306  * gets a set of the composed nodes that constitute the ascendancy of this node, starting from root
307  * or from a particular ancestor
308  * \b WARNING : returned set is not sorted !
309  * @param  levelToStop   composed node which is the oldest ancestor required
310  * @return               ascendancy, direct father first in set.
311  */
312
313 std::list<ComposedNode *> Node::getAllAscendanceOf(ComposedNode *levelToStop) const
314 {
315   list<ComposedNode *> ret;
316   if(this==levelToStop)
317     return ret;
318   for(ComposedNode *iter=_father;iter!=levelToStop && iter!=0; iter=iter->_father)
319       ret.push_back(iter);
320   return ret;
321 }
322
323 bool Node::operator>(const Node& other) const
324 {
325   const ComposedNode *iter=other._father;
326   while(iter!=0 && iter!=this)
327     iter=iter->_father;
328   return iter==this;
329 }
330
331 bool Node::operator<(const Node& other) const
332 {
333   const ComposedNode *iter=_father;
334   while(iter!=0 && iter!=(&other))
335     iter=iter->_father;
336   return iter==(&other);
337 }
338
339 /**
340  *  @return Implementation of node: C++, Python, CORBA...
341  *  _implementation is set by a derived class in a Runtime
342  *  it normally applies only to elementaryNodes and it is used by Ports to select Data Converters.
343  *  Potential problem with Ports attached to composed Nodes...
344  */
345
346 string Node::getImplementation() const
347 {
348   return _implementation;
349 }
350
351 //! Becomes deprecated soon. Replaced by ComposedNode::CheckConsistency.
352 set<InputPort *> Node::edGetSetOfUnitializedInputPort() const
353 {
354   set<InputPort *> setOfUnitializedInputPort;
355   list<InputPort *> allOfInputPorts=getSetOfInputPort();
356   for(list<InputPort *>::const_iterator iter=allOfInputPorts.begin();iter!=allOfInputPorts.end();iter++)
357     {
358       if ( ! (*iter)->edIsInitialized() )
359         setOfUnitializedInputPort.insert(*iter);
360     }
361   return setOfUnitializedInputPort;
362 }
363
364 //! Becomes deprecated soon. Replaced by ComposedNode::CheckConsistency.
365 bool Node::edAreAllInputPortInitialized() const
366 {
367   set<InputPort *> setOfUnitializedInputPort = edGetSetOfUnitializedInputPort();
368   return ( setOfUnitializedInputPort.size() == 0);
369 }
370
371 /*!
372  * Called typically by Bloc to notify failure on potentially next nodes on the same scope of 'this'
373  */
374 void Node::exForwardFailed()
375 {
376   _outGate.exNotifyFailed();
377 }
378
379 /*!
380  * Called typically by Bloc to activate potentially next nodes on the same scope of 'this'
381  */
382 void Node::exForwardFinished()
383 {
384   DEBTRACE("Node::exForwardFinished");
385   _outGate.exNotifyDone();
386 }
387
388 /*!
389  * Called typically by ComposedNode to correctly update DF/CF/DS links
390  */
391 void Node::edDisconnectAllLinksWithMe()
392 {
393   _inGate.edDisconnectAllLinksToMe();
394   _outGate.edDisconnectAllLinksFromMe();
395 }
396
397 Proc *Node::getProc()
398 {
399   if(!_father)
400     return 0;
401   return _father->getProc();
402 }
403
404 const Proc * Node::getProc() const
405 {
406   if(!_father)
407     return 0;
408   return _father->getProc();
409 }
410
411 ComposedNode *Node::getRootNode() const throw(YACS::Exception)
412 {
413   if(!_father)
414     throw Exception("No root node");
415   ComposedNode *iter=_father;
416   while(iter->_father)
417     iter=iter->_father;
418   return (ComposedNode *)iter;
419 }
420
421 /**
422  * checks validity of ports name, that must not contain a particular character '?'
423  * USAGE NOT CLEAR, not used so far, when are those characters set ?
424  */
425
426 void Node::checkValidityOfPortName(const std::string& name) throw(YACS::Exception)
427 {
428   if(name.find(SEP_CHAR_IN_PORT, 0 )!=string::npos)
429     {
430       string what("Port name "); what+=name; what+="not valid because it contains character "; what+=SEP_CHAR_IN_PORT;
431       throw Exception(what);
432     }
433 }
434
435 /**
436  * @note : Check that 'node1' and 'node2' have exactly the same father
437  * @exception : If 'node1' and 'node2' have NOT exactly the same father
438  */
439 ComposedNode *Node::checkHavingCommonFather(Node *node1, Node *node2) throw(YACS::Exception)
440 {
441   if(node1!=0 && node2!=0)
442     {
443       if(node1->_father==node2->_father)
444         return node1->_father;
445     }
446   throw Exception("check failed : nodes have not the same father");
447 }
448
449 const std::string Node::getId() const
450 {
451     std::string id=getRootNode()->getName();
452     if(getRootNode() != this)
453       id= id+'.'+ getRootNode()->getChildName(this);
454     string::size_type debut =id.find_first_of('.');
455     while(debut != std::string::npos){
456         id[debut]='_';
457         debut=id.find_first_of('.',debut);
458     }
459     return id;
460 }
461
462 void Node::setProperty(const std::string& name, const std::string& value)
463 {
464     DEBTRACE("Node::setProperty " << name << " " << value);
465     _propertyMap[name]=value;
466 }
467
468 std::string Node::getProperty(const std::string& name)
469 {
470   std::map<std::string,std::string>::iterator it=_propertyMap.find(name);
471
472   if(it != _propertyMap.end())
473     return it->second;
474   else if(_father)
475     return _father->getProperty(name);
476   else
477     return "";
478 }
479
480 std::map<std::string,std::string> Node::getProperties()
481 {
482   std::map<std::string,std::string> amap=_propertyMap;
483   if(_father)
484     {
485       std::map<std::string,std::string> fatherMap=_father->getProperties();
486       amap.insert(fatherMap.begin(),fatherMap.end());
487     }
488
489   return amap;
490 }
491
492 void Node::setProperties(std::map<std::string,std::string> properties)
493 {
494   _propertyMap.clear();
495   _propertyMap=properties;
496 }
497
498 //! Return the node state in the context of its father
499 /*!
500  * \return the effective node state
501  *
502  * The node state is stored in a private attribute _state.
503  * This state is relative to its father state : a node with a
504  * TOACTIVATE state with a father node in a READY state is not
505  * to activate. Its effective state is only READY.
506  * This method returns the effective state of the node taking
507  * into account that of its father.
508  */
509 YACS::StatesForNode Node::getEffectiveState() const
510 {
511   if(!_father)   //the root node
512     return _state;
513   if(_state==YACS::DISABLED)
514     return YACS::DISABLED;
515   return _father->getEffectiveState(this);
516 }
517
518 //! Return the effective state of a node in the context of this one (its father)
519 /*!
520  * \param node: the node which effective state is queried
521  * \return the effective node state
522  */
523 YACS::StatesForNode Node::getEffectiveState(const Node* node) const
524 {
525   if(node->getState()==YACS::DISABLED)
526     return YACS::DISABLED;
527
528   YACS::StatesForNode effectiveState=getEffectiveState();
529   switch(effectiveState)
530     {
531     case YACS::READY:
532       return YACS::READY;
533     case YACS::TOACTIVATE:
534       return YACS::READY;
535     case YACS::DISABLED:
536       return YACS::DISABLED;
537     case YACS::ERROR:
538       return YACS::FAILED;
539     default:
540       return node->getState();
541     }
542 }
543
544 //! Return the color associated to a state
545 /*!
546  * \param state : the node state
547  * \return the associated color
548  */
549 std::string Node::getColorState(YACS::StatesForNode state) const
550 {
551   switch(state)
552     {
553     case YACS::READY:
554       return "pink";
555     case YACS::TOLOAD:
556       return "magenta";
557     case YACS::LOADED:
558       return "magenta";
559     case YACS::TOACTIVATE:
560       return "purple";
561     case YACS::ACTIVATED:
562       return "blue";
563     case YACS::DONE:
564       return "green";
565     case YACS::ERROR:
566       return "red";
567     case YACS::FAILED:
568       return "orange";
569     case YACS::DISABLED:
570       return "grey";
571     case YACS::PAUSE:
572       return "white";
573     default:
574       return "white";
575     }
576 }
577
578 //! Dump to the input stream a dot representation of the node
579 /*!
580  *  \param os : the input stream
581  */
582 void Node::writeDot(std::ostream &os) const
583 {
584   os << getId() << "[fillcolor=\"" ;
585   YACS::StatesForNode state=getEffectiveState();
586   os << getColorState(state);
587   os << "\" label=\"" << getImplementation() << "Node:" ;
588   os << getQualifiedName() <<"\"];\n";
589 }
590
591 //! same as Node::getName() in most cases, but differs for children of switch
592 /*!
593  *  used by writeDot to distinguish children of switch, by adding a prefix to the name.
594  *  prefix is built on case id.
595  */
596
597 std::string Node::getQualifiedName() const
598 {
599   if(_father)
600     return _father->getMyQualifiedName(this);
601   return getName();
602 }
603
604 //! return node instance identifiant, unique for each node instance 
605 /*!
606  * node instance identifiant is used to check if to nodes pointers refers to the same instance
607  */ 
608 int Node::getNumId()
609 {
610   return _numId;
611 }
612
613 //! Sets the given state for node.
614 /*! It is strongly recommended to use this function if you want to
615  *  change the state of the node, instead of direct access to _state field (_state = ...).
616  */
617 void Node::setState(YACS::StatesForNode theState)
618 {
619   DEBTRACE("Node::setState: " << getName() << " " << theState);
620   _state = theState;
621   // emit notification to all observers registered with the dispatcher on any change of the node's state
622   sendEvent("status");
623 }
624
625 std::vector<std::pair<std::string,int> > Node::getDPLScopeInfo(ComposedNode *gfn)
626
627   std::vector< std::pair<std::string,int> > ret;
628   Node *work2(this);
629   ComposedNode *work(getFather());
630   while(work!=gfn && work!=0)
631     {
632       DynParaLoop *workc(dynamic_cast<DynParaLoop *>(work));
633       if(workc)
634         {
635           std::pair<std::string,int> p(gfn->getChildName(workc),workc->getBranchIDOfNode(work2));
636           ret.push_back(p);
637         }
638       work2=work;
639       work=work->getFather();
640     }
641   return ret;
642 }
643
644 /*!
645  * Method called by the Executor only if the executor is sensitive of scope of DynParaLoop.
646  * This method is virtual and empty because by default nothing is done.
647  */
648 void Node::applyDPLScope(ComposedNode *gfn)
649 {
650 }
651
652 //! emit notification to all observers registered with  the dispatcher 
653 /*!
654  * The dispatcher is unique and can be obtained by getDispatcher()
655  */
656 void Node::sendEvent(const std::string& event)
657 {
658   DEBTRACE("Node::sendEvent " << event);
659   Dispatcher* disp=Dispatcher::getDispatcher();
660   disp->dispatch(this,event);
661 }
662
663 //! emit notification to all observers registered with  the dispatcher 
664 /*!
665  * The dispatcher is unique and can be obtained by getDispatcher()
666  */
667 void Node::sendEvent2(const std::string& event, void *something)
668 {
669   Dispatcher* disp=Dispatcher::getDispatcher();
670   disp->dispatch2(this,event,something);
671 }
672
673 /*!
674  *  For use only when loading a previously saved execution
675  */
676
677 void YACS::ENGINE::StateLoader(Node* node, YACS::StatesForNode state)
678 {
679   node->setState(state);
680 }
681
682 //! indicates if the node is valid (returns 1) or not (returns 0)
683 /*!
684  * This method is useful when editing a schema. It has no meaning in execution.
685  * When a node is edited, its modified method must be called so when isValid is called, its state
686  * is updated (call to edUpdateState) before returning the validity check
687  */
688 int Node::isValid()
689 {
690   if(_modified)
691     edUpdateState();
692   if(_state > YACS::INVALID)
693     return 1;
694   else
695     return 0;
696 }
697
698 //! update the status of the node
699 /*!
700  * Only useful when editing a schema
701  * Do nothing in base Node : to implement in derived classes
702  */
703 void Node::edUpdateState()
704 {
705   DEBTRACE("Node::edUpdateState(): " << _modified);
706   _modified=0;
707 }
708
709 //! returns a string that contains an error report if the node is in error
710 /*!
711  * 
712  */
713 std::string Node::getErrorReport()
714 {
715   if(getState()==YACS::DISABLED)
716     return "<error node= "+getName()+ "state= DISABLED/>\n";
717
718   YACS::StatesForNode effectiveState=getEffectiveState();
719
720   DEBTRACE("Node::getErrorReport: " << getName() << " " << effectiveState << " " << _errorDetails);
721   if(effectiveState != YACS::INVALID &&  effectiveState != YACS::ERROR && 
722      effectiveState != YACS::FAILED && effectiveState != YACS::INTERNALERR)
723     return "";
724
725   std::string report="<error node= " ;
726   report=report + getName() ;
727   switch(effectiveState)
728     {
729     case YACS::INVALID:
730       report=report+" state= INVALID";
731       break;
732     case YACS::ERROR:
733       report=report+" state= ERROR";
734       break;
735     case YACS::FAILED:
736       report=report+" state= FAILED";
737       break;
738     case YACS::INTERNALERR:
739       report=report+" state= INTERNALERR";
740       break;
741     default:
742       break;
743     }
744   report=report + ">\n" ;
745   report=report+_errorDetails;
746   report=report+"\n</error>";
747   return report;
748 }
749
750 //! returns a string that contains the name of the container log file if it exists
751 /*!
752  * Do nothing here. To subclass
753  */
754 std::string Node::getContainerLog()
755 {
756   return "";
757 }
758
759 //! Sets Node in modified state and its father if it exists
760 /*!
761  * 
762  */
763 void Node::modified()
764 {
765   DEBTRACE("Node::modified() " << getName());
766   _modified=1;
767   if(_father)
768     _father->modified();
769 }
770
771 //! Put this node into TOLOAD state when possible
772 /*!
773  * 
774  */
775 void Node::ensureLoading()
776 {
777   if(_state == YACS::READY)
778     setState(YACS::TOLOAD);
779 }
780
781 //! Return the name of a state
782 /*!
783  * 
784  */
785 std::string Node::getStateName(YACS::StatesForNode state)
786 {
787   static NodeStateNameMap nodeStateNameMap;
788   return nodeStateNameMap[state];
789 }
790
791 //! Stop all pending activities of the node
792 /*!
793  * This method should be called when a Proc is finished and must be deleted from the YACS server
794  */
795 void Node::shutdown(int level)
796 {
797   if(level==0)return;
798 }
799
800 //! Clean the node in case of not clean exit
801 /*!
802  * This method should be called on a control-C or sigterm
803  */
804 void Node::cleanNodes()
805 {
806 }
807
808 //! Reset the node state depending on the parameter level
809 void Node::resetState(int level)
810 {
811   DEBTRACE("Node::resetState " << getName() << "," << level << "," << _state);
812   if(_state==YACS::ERROR || _state==YACS::FAILED || _state==YACS::ACTIVATED)
813     {
814       setState(YACS::READY);
815       InGate* inGate = getInGate();
816       std::list<OutGate*> backlinks = inGate->getBackLinks();
817       for (std::list<OutGate*>::iterator io = backlinks.begin(); io != backlinks.end(); io++)
818         {
819           Node* fromNode = (*io)->getNode();
820           if(fromNode->getState() == YACS::DONE)
821             {
822               inGate->setPrecursorDone(*io);
823             }
824         }
825     }
826 }