]> SALOME platform Git repositories - modules/yacs.git/blob - src/engine/Node.cxx
Salome HOME
[EDF12520] : Optimization of placements of Kernel containers in ForEachLoop/HP Contai...
[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 DynParaLoop *Node::getClosestDPLAmongAncestors() const
412 {
413   if(!_father)
414     return NULL;
415   ComposedNode *iter(_father);
416   do
417     {
418       DynParaLoop *iter2(dynamic_cast<DynParaLoop *>(iter));
419       if(iter2)
420         return iter2;
421       iter=iter->_father;
422     }
423   while(iter);
424   return NULL;
425 }
426
427 ComposedNode *Node::getRootNode() const throw(YACS::Exception)
428 {
429   if(!_father)
430     throw Exception("No root node");
431   ComposedNode *iter=_father;
432   while(iter->_father)
433     iter=iter->_father;
434   return (ComposedNode *)iter;
435 }
436
437 /**
438  * checks validity of ports name, that must not contain a particular character '?'
439  * USAGE NOT CLEAR, not used so far, when are those characters set ?
440  */
441
442 void Node::checkValidityOfPortName(const std::string& name) throw(YACS::Exception)
443 {
444   if(name.find(SEP_CHAR_IN_PORT, 0 )!=string::npos)
445     {
446       string what("Port name "); what+=name; what+="not valid because it contains character "; what+=SEP_CHAR_IN_PORT;
447       throw Exception(what);
448     }
449 }
450
451 /**
452  * @note : Check that 'node1' and 'node2' have exactly the same father
453  * @exception : If 'node1' and 'node2' have NOT exactly the same father
454  */
455 ComposedNode *Node::checkHavingCommonFather(Node *node1, Node *node2) throw(YACS::Exception)
456 {
457   if(node1!=0 && node2!=0)
458     {
459       if(node1->_father==node2->_father)
460         return node1->_father;
461     }
462   throw Exception("check failed : nodes have not the same father");
463 }
464
465 const std::string Node::getId() const
466 {
467     std::string id=getRootNode()->getName();
468     if(getRootNode() != this)
469       id= id+'.'+ getRootNode()->getChildName(this);
470     string::size_type debut =id.find_first_of('.');
471     while(debut != std::string::npos){
472         id[debut]='_';
473         debut=id.find_first_of('.',debut);
474     }
475     return id;
476 }
477
478 void Node::setProperty(const std::string& name, const std::string& value)
479 {
480     DEBTRACE("Node::setProperty " << name << " " << value);
481     _propertyMap[name]=value;
482 }
483
484 std::string Node::getProperty(const std::string& name)
485 {
486   std::map<std::string,std::string>::iterator it=_propertyMap.find(name);
487
488   if(it != _propertyMap.end())
489     return it->second;
490   else if(_father)
491     return _father->getProperty(name);
492   else
493     return "";
494 }
495
496 std::map<std::string,std::string> Node::getProperties()
497 {
498   std::map<std::string,std::string> amap=_propertyMap;
499   if(_father)
500     {
501       std::map<std::string,std::string> fatherMap=_father->getProperties();
502       amap.insert(fatherMap.begin(),fatherMap.end());
503     }
504
505   return amap;
506 }
507
508 void Node::setProperties(std::map<std::string,std::string> properties)
509 {
510   _propertyMap.clear();
511   _propertyMap=properties;
512 }
513
514 //! Return the node state in the context of its father
515 /*!
516  * \return the effective node state
517  *
518  * The node state is stored in a private attribute _state.
519  * This state is relative to its father state : a node with a
520  * TOACTIVATE state with a father node in a READY state is not
521  * to activate. Its effective state is only READY.
522  * This method returns the effective state of the node taking
523  * into account that of its father.
524  */
525 YACS::StatesForNode Node::getEffectiveState() const
526 {
527   if(!_father)   //the root node
528     return _state;
529   if(_state==YACS::DISABLED)
530     return YACS::DISABLED;
531   return _father->getEffectiveState(this);
532 }
533
534 //! Return the effective state of a node in the context of this one (its father)
535 /*!
536  * \param node: the node which effective state is queried
537  * \return the effective node state
538  */
539 YACS::StatesForNode Node::getEffectiveState(const Node* node) const
540 {
541   if(node->getState()==YACS::DISABLED)
542     return YACS::DISABLED;
543
544   YACS::StatesForNode effectiveState=getEffectiveState();
545   switch(effectiveState)
546     {
547     case YACS::READY:
548       return YACS::READY;
549     case YACS::TOACTIVATE:
550       return YACS::READY;
551     case YACS::DISABLED:
552       return YACS::DISABLED;
553     case YACS::ERROR:
554       return YACS::FAILED;
555     default:
556       return node->getState();
557     }
558 }
559
560 //! Return the color associated to a state
561 /*!
562  * \param state : the node state
563  * \return the associated color
564  */
565 std::string Node::getColorState(YACS::StatesForNode state) const
566 {
567   switch(state)
568     {
569     case YACS::READY:
570       return "pink";
571     case YACS::TOLOAD:
572       return "magenta";
573     case YACS::LOADED:
574       return "magenta";
575     case YACS::TOACTIVATE:
576       return "purple";
577     case YACS::ACTIVATED:
578       return "blue";
579     case YACS::DONE:
580       return "green";
581     case YACS::ERROR:
582       return "red";
583     case YACS::FAILED:
584       return "orange";
585     case YACS::DISABLED:
586       return "grey";
587     case YACS::PAUSE:
588       return "white";
589     default:
590       return "white";
591     }
592 }
593
594 //! Dump to the input stream a dot representation of the node
595 /*!
596  *  \param os : the input stream
597  */
598 void Node::writeDot(std::ostream &os) const
599 {
600   os << getId() << "[fillcolor=\"" ;
601   YACS::StatesForNode state=getEffectiveState();
602   os << getColorState(state);
603   os << "\" label=\"" << getImplementation() << "Node:" ;
604   os << getQualifiedName() <<"\"];\n";
605 }
606
607 //! same as Node::getName() in most cases, but differs for children of switch
608 /*!
609  *  used by writeDot to distinguish children of switch, by adding a prefix to the name.
610  *  prefix is built on case id.
611  */
612
613 std::string Node::getQualifiedName() const
614 {
615   if(_father)
616     return _father->getMyQualifiedName(this);
617   return getName();
618 }
619
620 //! return node instance identifiant, unique for each node instance 
621 /*!
622  * node instance identifiant is used to check if to nodes pointers refers to the same instance
623  */ 
624 int Node::getNumId()
625 {
626   return _numId;
627 }
628
629 //! Sets the given state for node.
630 /*! It is strongly recommended to use this function if you want to
631  *  change the state of the node, instead of direct access to _state field (_state = ...).
632  */
633 void Node::setState(YACS::StatesForNode theState)
634 {
635   DEBTRACE("Node::setState: " << getName() << " " << theState);
636   _state = theState;
637   // emit notification to all observers registered with the dispatcher on any change of the node's state
638   sendEvent("status");
639 }
640
641 std::vector<std::pair<std::string,int> > Node::getDPLScopeInfo(ComposedNode *gfn)
642
643   std::vector< std::pair<std::string,int> > ret;
644   Node *work2(this);
645   ComposedNode *work(getFather());
646   while(work!=gfn && work!=0)
647     {
648       DynParaLoop *workc(dynamic_cast<DynParaLoop *>(work));
649       if(workc)
650         {
651           std::pair<std::string,int> p(gfn->getChildName(workc),workc->getBranchIDOfNode(work2));
652           ret.push_back(p);
653         }
654       work2=work;
655       work=work->getFather();
656     }
657   return ret;
658 }
659
660 /*!
661  * Method called by the Executor only if the executor is sensitive of scope of DynParaLoop.
662  * This method is virtual and empty because by default nothing is done.
663  */
664 void Node::applyDPLScope(ComposedNode *gfn)
665 {
666 }
667
668 //! emit notification to all observers registered with  the dispatcher 
669 /*!
670  * The dispatcher is unique and can be obtained by getDispatcher()
671  */
672 void Node::sendEvent(const std::string& event)
673 {
674   DEBTRACE("Node::sendEvent " << event);
675   Dispatcher* disp=Dispatcher::getDispatcher();
676   disp->dispatch(this,event);
677 }
678
679 //! emit notification to all observers registered with  the dispatcher 
680 /*!
681  * The dispatcher is unique and can be obtained by getDispatcher()
682  */
683 void Node::sendEvent2(const std::string& event, void *something)
684 {
685   Dispatcher* disp=Dispatcher::getDispatcher();
686   disp->dispatch2(this,event,something);
687 }
688
689 /*!
690  *  For use only when loading a previously saved execution
691  */
692
693 void YACS::ENGINE::StateLoader(Node* node, YACS::StatesForNode state)
694 {
695   node->setState(state);
696 }
697
698 //! indicates if the node is valid (returns 1) or not (returns 0)
699 /*!
700  * This method is useful when editing a schema. It has no meaning in execution.
701  * When a node is edited, its modified method must be called so when isValid is called, its state
702  * is updated (call to edUpdateState) before returning the validity check
703  */
704 int Node::isValid()
705 {
706   if(_modified)
707     edUpdateState();
708   if(_state > YACS::INVALID)
709     return 1;
710   else
711     return 0;
712 }
713
714 //! update the status of the node
715 /*!
716  * Only useful when editing a schema
717  * Do nothing in base Node : to implement in derived classes
718  */
719 void Node::edUpdateState()
720 {
721   DEBTRACE("Node::edUpdateState(): " << _modified);
722   _modified=0;
723 }
724
725 //! returns a string that contains an error report if the node is in error
726 /*!
727  * 
728  */
729 std::string Node::getErrorReport()
730 {
731   if(getState()==YACS::DISABLED)
732     return "<error node= "+getName()+ "state= DISABLED/>\n";
733
734   YACS::StatesForNode effectiveState=getEffectiveState();
735
736   DEBTRACE("Node::getErrorReport: " << getName() << " " << effectiveState << " " << _errorDetails);
737   if(effectiveState != YACS::INVALID &&  effectiveState != YACS::ERROR && 
738      effectiveState != YACS::FAILED && effectiveState != YACS::INTERNALERR)
739     return "";
740
741   std::string report="<error node= " ;
742   report=report + getName() ;
743   switch(effectiveState)
744     {
745     case YACS::INVALID:
746       report=report+" state= INVALID";
747       break;
748     case YACS::ERROR:
749       report=report+" state= ERROR";
750       break;
751     case YACS::FAILED:
752       report=report+" state= FAILED";
753       break;
754     case YACS::INTERNALERR:
755       report=report+" state= INTERNALERR";
756       break;
757     default:
758       break;
759     }
760   report=report + ">\n" ;
761   report=report+_errorDetails;
762   report=report+"\n</error>";
763   return report;
764 }
765
766 //! returns a string that contains the name of the container log file if it exists
767 /*!
768  * Do nothing here. To subclass
769  */
770 std::string Node::getContainerLog()
771 {
772   return "";
773 }
774
775 //! Sets Node in modified state and its father if it exists
776 /*!
777  * 
778  */
779 void Node::modified()
780 {
781   DEBTRACE("Node::modified() " << getName());
782   _modified=1;
783   if(_father)
784     _father->modified();
785 }
786
787 //! Put this node into TOLOAD state when possible
788 /*!
789  * 
790  */
791 void Node::ensureLoading()
792 {
793   if(_state == YACS::READY)
794     setState(YACS::TOLOAD);
795 }
796
797 //! Return the name of a state
798 /*!
799  * 
800  */
801 std::string Node::getStateName(YACS::StatesForNode state)
802 {
803   static NodeStateNameMap nodeStateNameMap;
804   return nodeStateNameMap[state];
805 }
806
807 //! Stop all pending activities of the node
808 /*!
809  * This method should be called when a Proc is finished and must be deleted from the YACS server
810  */
811 void Node::shutdown(int level)
812 {
813   if(level==0)return;
814 }
815
816 //! Clean the node in case of not clean exit
817 /*!
818  * This method should be called on a control-C or sigterm
819  */
820 void Node::cleanNodes()
821 {
822 }
823
824 //! Reset the node state depending on the parameter level
825 void Node::resetState(int level)
826 {
827   DEBTRACE("Node::resetState " << getName() << "," << level << "," << _state);
828   if(_state==YACS::ERROR || _state==YACS::FAILED || _state==YACS::ACTIVATED)
829     {
830       setState(YACS::READY);
831       InGate* inGate = getInGate();
832       std::list<OutGate*> backlinks = inGate->getBackLinks();
833       for (std::list<OutGate*>::iterator io = backlinks.begin(); io != backlinks.end(); io++)
834         {
835           Node* fromNode = (*io)->getNode();
836           if(fromNode->getState() == YACS::DONE)
837             {
838               inGate->setPrecursorDone(*io);
839             }
840         }
841     }
842 }