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