1 // Copyright (C) 2006-2008 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "InputPort.hxx"
21 #include "OutputPort.hxx"
22 #include "ComposedNode.hxx"
23 #include "Dispatcher.hxx"
24 #include "InputDataStreamPort.hxx"
25 #include "OutputDataStreamPort.hxx"
29 #include "YacsTrace.hxx"
31 using namespace YACS::ENGINE;
34 const char Node::SEP_CHAR_IN_PORT[]=".";
37 std::map<int,Node*> Node::idMap;
38 std::map<int, std::string> Node::_nodeStateName;
40 Node::Node(const std::string& name):_name(name),_inGate(this),_outGate(this),_father(0),_state(YACS::READY),
41 _implementation(Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME),_modified(1)
43 // Should be protected by lock ??
48 Node::Node(const Node& other, ComposedNode *father):_inGate(this),_outGate(this),_name(other._name),_father(father),
49 _state(YACS::READY),_implementation(other._implementation),
50 _propertyMap(other._propertyMap),_modified(other._modified)
61 * initialisation of all input and output ports and gates, for execution
64 void Node::init(bool start)
68 if(_state == YACS::DISABLED)
70 exDisabledState(); // to refresh propagation of DISABLED state
73 setState(YACS::READY);
76 Node *Node::clone(ComposedNode *father, bool editionOnly) const
78 Node *ret=simpleClone(father,editionOnly);
79 ret->performDuplicationOfPlacement(*this);
83 //! Change the name of the node
85 * raise an exception if the name is already used in the scope of its father
86 * \param name : the new name
88 void Node::setName(const std::string& name)
92 if(_father->isNameAlreadyUsed(name))
94 if ( _father->getChildByName(name) != this )
96 std::string what("Name ");
98 what+=" already exists in the scope of "; what+=_father->getName();
99 throw Exception(what);
107 * get the set of all nodes connected to the outGate
110 set<Node *> Node::getOutNodes() const
113 set<InGate *> inGates=_outGate.edSetInGate();
114 for(set<InGate *>::iterator iter=inGates.begin();iter!=inGates.end();iter++)
115 ret.insert((*iter)->getNode());
119 bool Node::exIsControlReady() const
121 return _inGate.exIsReady();
124 //! Update the node state
126 * \note : Update the '_state' attribute.
127 * Typically called by 'this->_inGate' when 'this->_inGate' is ready.
129 * Called by InGate::exNotifyFromPrecursor
131 void Node::exUpdateState()
133 if(_state==YACS::DISABLED)return;
134 if(_inGate.exIsReady())
135 setState(YACS::TOACTIVATE);
138 //! Notify this node that its execution has failed
140 * The node goes in FAILED state and
141 * propagate the notification through the outGate port
144 void Node::exFailedState()
146 DEBTRACE( "Node::exFailedState: " << getName() );
147 setState(YACS::FAILED);
148 _outGate.exNotifyFailed();
151 //! Notify this node that it has been disabled
153 * The node goes in DISABLED state and
154 * propagate the notification through the outGate port
157 void Node::exDisabledState()
159 DEBTRACE( "Node::exDisabledState: " << getName() );
160 setState(YACS::DISABLED);
161 _outGate.exNotifyDisabled();
164 InPort *Node::getInPort(const std::string& name) const throw(Exception)
169 ret=getInputPort(name);
173 ret=getInputDataStreamPort(name);
179 * \note: Contrary to getOutputPort method, this method returns the output port at highest level, possible.
180 * That is to say in some ComposedNode, like ForEachLoop or Switch, an outport inside 'this' is seen differently than the true outport.
182 OutPort *Node::getOutPort(const std::string& name) const throw(Exception)
187 ret=getOutputPort(name);
191 ret=getOutputDataStreamPort(name);
196 std::list<InPort *> Node::getSetOfInPort() const
199 list<InputPort *> data=getSetOfInputPort();
200 ret.insert(ret.end(),data.begin(),data.end());
201 list<InputDataStreamPort *> ds=getSetOfInputDataStreamPort();
202 ret.insert(ret.end(),ds.begin(),ds.end());
206 std::list<OutPort *> Node::getSetOfOutPort() const
209 list<OutputPort *> data=getSetOfOutputPort();
210 ret.insert(ret.end(),data.begin(),data.end());
211 list<OutputDataStreamPort *> ds=getSetOfOutputDataStreamPort();
212 ret.insert(ret.end(),ds.begin(),ds.end());
217 * gets a set of the composed nodes that constitute the ascendancy of this node, starting from root
218 * or from a particular ancestor
219 * \b WARNING : returned set is not sorted !
220 * @param levelToStop composed node which is the oldest ancestor required
221 * @return ascendancy, direct father first in set.
224 std::list<ComposedNode *> Node::getAllAscendanceOf(ComposedNode *levelToStop) const
226 list<ComposedNode *> ret;
227 if(this==levelToStop)
229 for(ComposedNode *iter=_father;iter!=levelToStop && iter!=0; iter=iter->_father)
234 bool Node::operator>(const Node& other) const
236 const ComposedNode *iter=other._father;
237 while(iter!=0 && iter!=this)
242 bool Node::operator<(const Node& other) const
244 const ComposedNode *iter=_father;
245 while(iter!=0 && iter!=(&other))
247 return iter==(&other);
251 * @return Implementation of node: C++, Python, CORBA...
252 * _implementation is set by a derived class in a Runtime
253 * it normally applies only to elementaryNodes and it is used by Ports to select Data Converters.
254 * Potential problem with Ports attached to composed Nodes...
257 string Node::getImplementation() const
259 return _implementation;
262 //! Becomes deprecated soon. Replaced by ComposedNode::CheckConsistency.
263 set<InputPort *> Node::edGetSetOfUnitializedInputPort() const
265 set<InputPort *> setOfUnitializedInputPort;
266 list<InputPort *> allOfInputPorts=getSetOfInputPort();
267 for(list<InputPort *>::const_iterator iter=allOfInputPorts.begin();iter!=allOfInputPorts.end();iter++)
269 if ( ! (*iter)->edIsInitialized() )
270 setOfUnitializedInputPort.insert(*iter);
272 return setOfUnitializedInputPort;
275 //! Becomes deprecated soon. Replaced by ComposedNode::CheckConsistency.
276 bool Node::edAreAllInputPortInitialized() const
278 set<InputPort *> setOfUnitializedInputPort = edGetSetOfUnitializedInputPort();
279 return ( setOfUnitializedInputPort.size() == 0);
283 * Called typically by Bloc to notify failure on potentially next nodes on the same scope of 'this'
285 void Node::exForwardFailed()
287 _outGate.exNotifyFailed();
291 * Called typically by Bloc to activate potentially next nodes on the same scope of 'this'
293 void Node::exForwardFinished()
295 DEBTRACE("Node::exForwardFinished");
296 _outGate.exNotifyDone();
300 * Called typically by ComposedNode to correctly update DF/CF/DS links
302 void Node::edDisconnectAllLinksWithMe()
304 _inGate.edDisconnectAllLinksToMe();
305 _outGate.edDisconnectAllLinksFromMe();
308 ComposedNode *Node::getRootNode() const throw(Exception)
311 throw Exception("No root node");
312 ComposedNode *iter=_father;
315 return (ComposedNode *)iter;
319 * checks validity of ports name, that must not contain a particular character '?'
320 * USAGE NOT CLEAR, not used so far, when are those characters set ?
323 void Node::checkValidityOfPortName(const std::string& name) throw(Exception)
325 if(name.find(SEP_CHAR_IN_PORT, 0 )!=string::npos)
327 string what("Port name "); what+=name; what+="not valid because it contains character "; what+=SEP_CHAR_IN_PORT;
328 throw Exception(what);
333 * @note : Check that 'node1' and 'node2' have exactly the same father
334 * @exception : If 'node1' and 'node2' have NOT exactly the same father
336 ComposedNode *Node::checkHavingCommonFather(Node *node1, Node *node2) throw(Exception)
338 if(node1!=0 && node2!=0)
340 if(node1->_father==node2->_father)
341 return node1->_father;
343 throw Exception("check failed : nodes have not the same father");
346 const std::string Node::getId() const
348 std::string id=getRootNode()->getName();
349 if(getRootNode() != this)
350 id= id+'.'+ getRootNode()->getChildName(this);
351 string::size_type debut =id.find_first_of('.');
352 while(debut != std::string::npos){
354 debut=id.find_first_of('.',debut);
359 void Node::setProperty(const std::string& name, const std::string& value)
361 _propertyMap[name]=value;
364 //! Return the node state in the context of its father
366 * \return the effective node state
368 * The node state is stored in a private attribute _state.
369 * This state is relative to its father state : a node with a
370 * TOACTIVATE state with a father node in a READY state is not
371 * to activate. Its effective state is only READY.
372 * This method returns the effective state of the node taking
373 * into account that of its father.
375 YACS::StatesForNode Node::getEffectiveState() const
377 if(!_father) //the root node
379 if(_state==YACS::DISABLED)
380 return YACS::DISABLED;
381 return _father->getEffectiveState(this);
384 //! Return the effective state of a node in the context of this one (its father)
386 * \param node: the node which effective state is queried
387 * \return the effective node state
389 YACS::StatesForNode Node::getEffectiveState(const Node* node) const
391 if(node->getState()==YACS::DISABLED)
392 return YACS::DISABLED;
394 YACS::StatesForNode effectiveState=getEffectiveState();
395 switch(effectiveState)
399 case YACS::TOACTIVATE:
402 return YACS::DISABLED;
406 return node->getState();
410 //! Return the color associated to a state
412 * \param state : the node state
413 * \return the associated color
415 std::string Node::getColorState(YACS::StatesForNode state) const
425 case YACS::TOACTIVATE:
427 case YACS::ACTIVATED:
444 //! Dump to the input stream a dot representation of the node
446 * \param os : the input stream
448 void Node::writeDot(std::ostream &os) const
450 os << getId() << "[fillcolor=\"" ;
451 YACS::StatesForNode state=getEffectiveState();
452 os << getColorState(state);
453 os << "\" label=\"" << getImplementation() << "Node:" ;
454 os << getQualifiedName() <<"\"];\n";
457 //! same as Node::getName() in most cases, but differs for children of switch
459 * used by writeDot to distinguish children of switch, by adding a prefix to the name.
460 * prefix is built on case id.
463 std::string Node::getQualifiedName() const
466 return _father->getMyQualifiedName(this);
470 //! return node instance identifiant, unique for each node instance
472 * node instance identifiant is used to check if to nodes pointers refers to the same instance
479 //! Sets the given state for node.
480 /*! It is strongly recommended to use this function if you want to
481 * change the state of the node, instead of direct access to _state field (_state = ...).
483 void Node::setState(YACS::StatesForNode theState)
485 DEBTRACE("Node::setState: " << getName() << " " << theState);
487 // emit notification to all observers registered with the dispatcher on any change of the node's state
491 //! emit notification to all observers registered with the dispatcher
493 * The dispatcher is unique and can be obtained by getDispatcher()
495 void Node::sendEvent(const std::string& event)
497 DEBTRACE("Node::sendEvent " << event);
498 Dispatcher* disp=Dispatcher::getDispatcher();
499 disp->dispatch(this,event);
503 * For use only when loading a previously saved execution
506 void YACS::ENGINE::StateLoader(Node* node, YACS::StatesForNode state)
508 node->setState(state);
511 //! indicates if the node is valid (returns 1) or not (returns 0)
513 * This method is useful when editing a schema. It has no meaning in execution.
514 * When a node is edited, its modified method must be called so when isValid is called, its state
515 * is updated (call to edUpdateState) before returning the validity check
521 if(_state > YACS::INVALID)
527 //! update the status of the node
529 * Only useful when editing a schema
530 * Do nothing in base Node : to implement in derived classes
532 void Node::edUpdateState()
534 DEBTRACE("Node::edUpdateState(): " << _modified);
538 //! returns a string that contains an error report if the node is in error
542 std::string Node::getErrorReport()
544 if(getState()==YACS::DISABLED)
545 return "<error node= "+getName()+ "state= DISABLED/>\n";
547 YACS::StatesForNode effectiveState=getEffectiveState();
549 DEBTRACE("Node::getErrorReport: " << getName() << " " << effectiveState << " " << _errorDetails);
550 if(effectiveState != YACS::INVALID && effectiveState != YACS::ERROR && effectiveState != YACS::FAILED)
553 std::string report="<error node= " ;
554 report=report + getName() ;
555 switch(effectiveState)
558 report=report+" state= INVALID";
561 report=report+" state= ERROR";
564 report=report+" state= FAILED";
569 report=report + ">\n" ;
570 report=report+_errorDetails;
571 report=report+"\n</error>";
575 //! returns a string that contains the name of the container log file if it exists
577 * Do nothing here. To subclass
579 std::string Node::getContainerLog()
584 //! Sets Node in modified state and its father if it exists
588 void Node::modified()
590 DEBTRACE("Node::modified() " << getName());
596 //! Put this node into TOLOAD state when possible
600 void Node::ensureLoading()
602 if(_state == YACS::READY)
603 setState(YACS::TOLOAD);
606 //! Return the name of a state
610 std::string Node::getStateName(YACS::StatesForNode state)
612 static bool map_init=false;
615 _nodeStateName[YACS::READY] ="READY";
616 _nodeStateName[YACS::TOLOAD] ="TOLOAD";
617 _nodeStateName[YACS::LOADED] ="LOADED";
618 _nodeStateName[YACS::TOACTIVATE] ="TOACTIVATE";
619 _nodeStateName[YACS::ACTIVATED] ="ACTIVATED";
620 _nodeStateName[YACS::DESACTIVATED] ="DESACTIVATED";
621 _nodeStateName[YACS::DONE] ="DONE";
622 _nodeStateName[YACS::SUSPENDED] ="SUSPENDED";
623 _nodeStateName[YACS::LOADFAILED] ="LOADFAILED";
624 _nodeStateName[YACS::EXECFAILED] ="EXECFAILED";
625 _nodeStateName[YACS::PAUSE] ="PAUSE";
626 _nodeStateName[YACS::INTERNALERR] ="INTERNALERR";
627 _nodeStateName[YACS::DISABLED] ="DISABLED";
628 _nodeStateName[YACS::FAILED] ="FAILED";
629 _nodeStateName[YACS::ERROR] ="ERROR";
631 return _nodeStateName[state];