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