Salome HOME
merge from branch DEV tag mergeto_trunk_04apr08
[modules/yacs.git] / src / engine / ElementaryNode.cxx
1 #include "ElementaryNode.hxx"
2 #include "Runtime.hxx"
3 #include "InputPort.hxx"
4 #include "OutputPort.hxx"
5 #include "ComposedNode.hxx"
6 #include "InputDataStreamPort.hxx"
7 #include "OutputDataStreamPort.hxx"
8 #include "Visitor.hxx"
9 #include <iostream>
10
11 //#define _DEVDEBUG_
12 #include "YacsTrace.hxx"
13
14 using namespace YACS::ENGINE;
15 using namespace std;
16
17 ElementaryNode::ElementaryNode(const std::string& name):Node(name)
18 {
19 }
20
21 ElementaryNode::ElementaryNode(const ElementaryNode& other, ComposedNode *father):Node(other,father)
22 {
23   for(list<InputPort *>::const_iterator iter1=other._setOfInputPort.begin();iter1!=other._setOfInputPort.end();iter1++)
24     _setOfInputPort.push_back((InputPort *)(*iter1)->clone(this));
25   for(list<OutputPort *>::const_iterator iter2=other._setOfOutputPort.begin();iter2!=other._setOfOutputPort.end();iter2++)
26     _setOfOutputPort.push_back((OutputPort *)(*iter2)->clone(this));
27   for(list<InputDataStreamPort *>::const_iterator iter3=other._setOfInputDataStreamPort.begin();iter3!=other._setOfInputDataStreamPort.end();iter3++)
28     _setOfInputDataStreamPort.push_back((InputDataStreamPort *)(*iter3)->clone(this));
29   for(list<OutputDataStreamPort *>::const_iterator iter4=other._setOfOutputDataStreamPort.begin();iter4!=other._setOfOutputDataStreamPort.end();iter4++)
30     _setOfOutputDataStreamPort.push_back((OutputDataStreamPort *)(*iter4)->clone(this));
31 }
32
33 void ElementaryNode::performDuplicationOfPlacement(const Node& other)
34 {
35 }
36
37 ElementaryNode::~ElementaryNode()
38 {
39   for(list<InputPort *>::iterator iter1=_setOfInputPort.begin();iter1!=_setOfInputPort.end();iter1++)
40     delete *iter1;
41   for(list<OutputPort *>::iterator iter2=_setOfOutputPort.begin();iter2!=_setOfOutputPort.end();iter2++)
42     delete *iter2;
43   for(list<InputDataStreamPort *>::iterator iter3=_setOfInputDataStreamPort.begin();iter3!=_setOfInputDataStreamPort.end();iter3++)
44     delete *iter3;
45   for(list<OutputDataStreamPort *>::iterator iter4=_setOfOutputDataStreamPort.begin();iter4!=_setOfOutputDataStreamPort.end();iter4++)
46     delete *iter4;
47 }
48
49 void ElementaryNode::init(bool start)
50 {
51   for(list<OutputPort *>::iterator iter=_setOfOutputPort.begin();iter!=_setOfOutputPort.end();iter++)
52     (*iter)->exInit();
53   for(list<InputPort *>::iterator iter2=_setOfInputPort.begin();iter2!=_setOfInputPort.end();iter2++)
54     (*iter2)->exInit(start);
55   _inGate.exReset();
56   if(_state == YACS::DISABLED)
57     {
58       exDisabledState(); // to refresh propagation of DISABLED state
59       return;
60     }
61   if(start) //complete initialization
62     setState(YACS::READY);
63   else //partial initialization (inside a loop)
64     setState(YACS::LOADED);
65 }
66
67 bool ElementaryNode::isDeployable() const
68 {
69   return false;
70 }
71
72 ComponentInstance *ElementaryNode::getComponent()
73 {
74   return 0;
75 }
76
77 YACS::StatesForNode ElementaryNode::getState() const
78 {
79   return Node::getState();
80 }
81
82 void ElementaryNode::exUpdateState()
83 {
84   DEBTRACE("ElementaryNode::exUpdateState: " << getName() << " " << _state );
85   if(_state==YACS::DISABLED)return;
86   if(_inGate.exIsReady())
87     if(areAllInputPortsValid())
88       {
89         if(_state == YACS::READY)
90           ensureLoading();
91         else if(_state == YACS::LOADED)
92           setState(YACS::TOACTIVATE);
93       }
94     else
95       {
96         string what("ElementaryNode::exUpdateState : Invalid graph given : Node with name \"");
97         what+=_name; what+="\" ready to run whereas some inputports are not set correctly\nCheck coherence DF/CF";
98         setState(YACS::INTERNALERR);
99         _errorDetails=what;
100         throw Exception(what);
101       }
102 }
103
104 int ElementaryNode::getNumberOfInputPorts() const
105 {
106   return _setOfInputPort.size();
107 }
108
109 int ElementaryNode::getNumberOfOutputPorts() const
110 {
111   return _setOfOutputPort.size();
112 }
113
114 InputPort *ElementaryNode::getInputPort(const std::string& name) const throw(Exception)
115 {
116   return getPort<InputPort>(name,_setOfInputPort);
117 }
118
119 OutputPort *ElementaryNode::getOutputPort(const std::string& name) const throw(Exception)
120 {
121   return getPort<OutputPort>(name,_setOfOutputPort);
122 }
123
124 std::set<OutPort *> ElementaryNode::getAllOutPortsLeavingCurrentScope() const
125 {
126   set<OutPort *> ret;
127   list<OutPort *> temp=getSetOfOutPort();
128   for(list<OutPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
129     {
130       set<InPort *> temp2=(*iter2)->edSetInPort();
131       if(temp2.size()!=0)
132         ret.insert(*iter2);
133     }
134   return ret;
135 }
136
137 std::set<InPort *> ElementaryNode::getAllInPortsComingFromOutsideOfCurrentScope() const
138 {
139   set<InPort *> ret;
140   list<InPort *> temp=getSetOfInPort();
141   for(list<InPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
142     {
143       set<OutPort *> temp2=(*iter2)->edSetOutPort();
144       if(temp2.size()!=0)
145         ret.insert(*iter2);
146     }
147   return ret;
148 }
149
150 std::vector< std::pair<OutPort *, InPort *> > ElementaryNode::getSetOfLinksLeavingCurrentScope() const
151 {
152   vector< pair<OutPort *, InPort *> > ret;
153   std::set<OutPort *> ports=getAllOutPortsLeavingCurrentScope();
154   for(set<OutPort *>::iterator iter2=ports.begin();iter2!=ports.end();iter2++)
155     {
156       set<InPort *> temp2=(*iter2)->edSetInPort();
157       for(set<InPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
158         ret.push_back(pair<OutPort *, InPort *>(*iter2,*iter3));
159     }
160   return ret;
161 }
162
163 std::vector< std::pair<InPort *, OutPort *> > ElementaryNode::getSetOfLinksComingInCurrentScope() const
164 {
165   vector< pair<InPort *, OutPort *> > ret;
166   set<InPort *> ports=getAllInPortsComingFromOutsideOfCurrentScope();
167   for(set<InPort *>::iterator iter2=ports.begin();iter2!=ports.end();iter2++)
168     {
169       set<OutPort *> temp2=(*iter2)->edSetOutPort();
170       for(set<OutPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
171         ret.push_back(pair<InPort *, OutPort *>(*iter2,*iter3));
172     }
173   return ret;
174 }
175
176 InputDataStreamPort *ElementaryNode::getInputDataStreamPort(const std::string& name) const throw(Exception)
177 {
178   return getPort<InputDataStreamPort>(name,_setOfInputDataStreamPort);
179 }
180
181 OutputDataStreamPort *ElementaryNode::getOutputDataStreamPort(const std::string& name) const throw(Exception)
182 {
183   return getPort<OutputDataStreamPort>(name,_setOfOutputDataStreamPort);
184 }
185
186 void ElementaryNode::edDisconnectAllLinksWithMe()
187 {
188   //CF
189   Node::edDisconnectAllLinksWithMe();
190   //Leaving part
191   // - DF
192   for(list<InputPort *>::iterator iter=_setOfInputPort.begin();iter!=_setOfInputPort.end();iter++)
193     (*iter)->edRemoveAllLinksLinkedWithMe();
194   // - DS
195   for(list<InputDataStreamPort *>::iterator iter2=_setOfInputDataStreamPort.begin();iter2!=_setOfInputDataStreamPort.end();iter2++)
196     (*iter2)->edRemoveAllLinksLinkedWithMe();
197   //Arriving part
198   // - DF
199   for(list<OutputPort *>::iterator iter=_setOfOutputPort.begin();iter!=_setOfOutputPort.end();iter++)
200     (*iter)->edRemoveAllLinksLinkedWithMe();
201   // - DS
202   for(list<OutputDataStreamPort *>::iterator iter2=_setOfOutputDataStreamPort.begin();iter2!=_setOfOutputDataStreamPort.end();iter2++)
203     (*iter2)->edRemoveAllLinksLinkedWithMe();
204 }
205
206 /**
207  * checks if all input ports contains a valid data. Used at execution to change the state of the node
208  * for activation.
209  */
210
211 bool ElementaryNode::areAllInputPortsValid() const
212 {
213   bool ret=true;
214   for(list<InputPort *>::const_iterator iter=_setOfInputPort.begin();iter!=_setOfInputPort.end();iter++)
215     {
216       ret=!(*iter)->isEmpty();
217       if (!ret) break;
218     }
219   return ret;
220 }
221
222 /**
223  * add this node task to a given set of ready tasks, if this task is ready to activate
224  */
225
226 void ElementaryNode::getReadyTasks(std::vector<Task *>& tasks)
227 {
228   DEBTRACE("ElementaryNode::getReadyTasks: " << getName() << " " << _state);
229   if(_state==YACS::TOACTIVATE or _state==YACS::TOLOAD)
230     tasks.push_back(this);
231 }
232
233 /**
234  * remove port from node at edition. Ports are typed.
235  */
236
237 void ElementaryNode::edRemovePort(Port *port) throw(Exception)
238 {
239   DEBTRACE("ElementaryNode::edRemovePort ");
240   if(port->getNode()!=this)
241     throw Exception("ElementaryNode::edRemovePort : Port is not held by this");
242   string typeOfPortInstance=port->getNameOfTypeOfCurrentInstance();
243   if(typeOfPortInstance==InputPort::NAME)
244     edRemovePortTypedFromSet<InputPort>(dynamic_cast<InputPort *>(port),_setOfInputPort);
245   else if(typeOfPortInstance==OutputPort::NAME)
246     edRemovePortTypedFromSet<OutputPort>(dynamic_cast<OutputPort *>(port),_setOfOutputPort);
247   else if(typeOfPortInstance==InputDataStreamPort::NAME)
248     edRemovePortTypedFromSet<InputDataStreamPort>(dynamic_cast<InputDataStreamPort *>(port),_setOfInputDataStreamPort);
249   else if(typeOfPortInstance==OutputDataStreamPort::NAME)
250     edRemovePortTypedFromSet<OutputDataStreamPort>(dynamic_cast<OutputDataStreamPort *>(port),_setOfOutputDataStreamPort);
251   else
252     throw Exception("ElementaryNode::edRemovePort : unknown port type");
253   delete port;
254   modified();
255 }
256
257 /**
258  * @return a set with only this node. (Same method in composed nodes)
259  */
260
261 list<ElementaryNode *> ElementaryNode::getRecursiveConstituents() const
262 {
263   list<ElementaryNode *> ret;
264   ret.push_back((ElementaryNode *)this);
265   return ret;
266 }
267
268 Node *ElementaryNode::getChildByName(const std::string& name) const throw(Exception)
269 {
270   string what("ElementaryNode does not agregate any nodes particullary node with name "); what+=name;
271   throw Exception(what);
272 }
273
274 void ElementaryNode::checkBasicConsistency() const throw(Exception)
275 {
276   DEBTRACE("ElementaryNode::checkBasicConsistency");
277   list<InputPort *>::const_iterator iter;
278   for(iter=_setOfInputPort.begin();iter!=_setOfInputPort.end();iter++)
279     (*iter)->checkBasicConsistency();  
280 }
281
282 ComposedNode *ElementaryNode::getDynClonerIfExists(const ComposedNode *levelToStop) const
283 {
284   for(ComposedNode *iter=_father;iter!=levelToStop && iter!=0; iter=iter->_father)
285     if(!iter->isPlacementPredictableB4Run())
286       return iter;
287   return 0;
288 }
289
290 InputPort *ElementaryNode::createInputPort(const std::string& inputPortName, TypeCode* type)
291 {
292   return getRuntime()->createInputPort(inputPortName, _implementation, this, type);
293 }
294
295 /**
296  * the input port is also published recursively in ancestors because it may be visible from everywhere.
297  * WARNING: CHECK CASE OF BLOC: ONLY INPUT PORTS NOT INTERNALLY CONNECTED MUST BE VISIBLE.
298  */
299
300 InputPort *ElementaryNode::edAddInputPort(const std::string& inputPortName, TypeCode* type) throw(Exception)
301 {
302   InputPort *ret = 0;
303   if (edCheckAddPort<InputPort, TypeCode*>(inputPortName,_setOfInputPort,type))
304     {
305       ret = createInputPort(inputPortName, type);
306       _setOfInputPort.push_back(ret);
307       modified();
308       /*
309       ComposedNode *iter=_father;
310       while(iter)
311         iter=iter->_father;
312         */
313     }
314   return ret;
315 }
316
317 OutputPort *ElementaryNode::createOutputPort(const std::string& outputPortName, TypeCode* type)
318 {
319   return getRuntime()->createOutputPort(outputPortName, _implementation, this, type);
320 }
321
322 /**
323  * TO SOLVE : The output port is not published in father. Father must create an output port.
324  * for now, publication is done the same way as input ports
325  */ 
326
327 OutputPort *ElementaryNode::edAddOutputPort(const std::string& outputPortName, TypeCode* type) throw(Exception)
328 {
329   OutputPort *ret =0;
330   if (edCheckAddPort<OutputPort, TypeCode*>(outputPortName,_setOfOutputPort,type))
331     {
332       ret = createOutputPort(outputPortName, type);
333       _setOfOutputPort.push_back(ret);
334       modified();
335       /*
336       ComposedNode *iter=_father;
337       while(iter)
338         iter=iter->_father;
339         */
340     }
341   return ret;
342 }
343
344 InputDataStreamPort *ElementaryNode::createInputDataStreamPort(const std::string& inputPortDSName, TypeCode* type)
345 {
346   return getRuntime()->createInputDataStreamPort(inputPortDSName, this, type);
347 }
348
349 InputDataStreamPort *ElementaryNode::edAddInputDataStreamPort(const std::string& inputPortDSName, TypeCode* type) throw(Exception)
350 {
351   InputDataStreamPort *ret = 0;
352   if (edCheckAddPort<InputDataStreamPort, TypeCode*>(inputPortDSName,_setOfInputDataStreamPort,type))
353     {
354       ret = createInputDataStreamPort(inputPortDSName, type);
355       _setOfInputDataStreamPort.push_back(ret);
356       modified();
357     }
358   return ret;
359 }
360
361 OutputDataStreamPort *ElementaryNode::createOutputDataStreamPort(const std::string& outputPortDSName, TypeCode* type)
362 {
363   return getRuntime()->createOutputDataStreamPort(outputPortDSName, this, type);
364 }
365
366 OutputDataStreamPort *ElementaryNode::edAddOutputDataStreamPort(const std::string& outputPortDSName, TypeCode* type) throw(Exception)
367 {
368   OutputDataStreamPort *ret = 0;
369   if (edCheckAddPort<OutputDataStreamPort, TypeCode*>(outputPortDSName,_setOfOutputDataStreamPort,type))
370     {
371       ret = createOutputDataStreamPort(outputPortDSName, type);
372       _setOfOutputDataStreamPort.push_back(ret);
373       modified();
374     }
375   return ret;
376 }
377
378 /**
379  * get the input port name used by the current node (see composed nodes)
380  */
381
382 string ElementaryNode::getInPortName(const InPort * inPort) const throw (Exception)
383 {
384   Node *node = inPort->getNode();
385   if ( node != this ) 
386     {
387       string what("InputPort "); what += inPort->getName(); what += " does not belong to node "; what += node->getName();
388       throw Exception(what);
389     }
390   return inPort->getName();
391 }
392
393 string ElementaryNode::getOutPortName(const OutPort *outPort) const throw (Exception)
394 {
395   Node *node = outPort->getNode();
396   if ( node != this ) 
397     {
398       string what("OutputPort "); what += outPort->getName(); what += " does not belong to node "; what += node->getName();
399       throw Exception(what);
400     }
401   return outPort->getName();
402 }
403
404 void ElementaryNode::begin()
405 {
406   setState(ACTIVATED);
407 }
408
409 bool ElementaryNode::isReady()
410 {
411   return _state==TOACTIVATE;
412 }
413
414 void ElementaryNode::finished()
415 {
416   setState(DONE);
417 }
418 void ElementaryNode::aborted()
419 {
420   setState(ERROR);
421 }
422
423 //! Notify this node that it is loaded
424 /*!
425  * When an elementary node has been loaded it goes to TOACTIVATE state
426  * It is then ready to be executed
427  *
428  */
429 void ElementaryNode::loaded()
430 {
431   setState(LOADED);
432   if(_inGate.exIsReady())
433     if(areAllInputPortsValid())
434       setState(TOACTIVATE);
435 }
436
437 void ElementaryNode::accept(Visitor *visitor)
438 {
439   visitor->visitElementaryNode(this);
440 }
441
442 //! Give a description of error when node status is ERROR
443 /*!
444  *
445  */
446 std::string ElementaryNode::getErrorDetails()
447 {
448   return _errorDetails;
449 }
450
451 void ElementaryNode::edUpdateState()
452 {
453   DEBTRACE("ElementaryNode::edUpdateState: " << getName());
454   YACS::StatesForNode state=YACS::READY;
455   try
456     {
457       checkBasicConsistency();
458       _errorDetails="";
459     }
460   catch(Exception& e)
461     {
462       state=YACS::INVALID;
463       _errorDetails=e.what();
464     }
465   DEBTRACE("ElementaryNode::edUpdateState: " << _errorDetails);
466   if(state != _state)
467     setState(state);
468   _modified=0;
469 }
470
471 //! Put this node into TOLOAD state when possible
472 /*!
473  * Can be called by another ElementaryNode that is connected to this one by a datastream link
474  * These 2 nodes must be loaded at the same time as they are coupled
475  * It's the other node which requests this node loading
476  */
477 void ElementaryNode::ensureLoading()
478 {
479   DEBTRACE("ElementaryNode::ensureLoading: " << getName());
480   if(_state != YACS::READY)
481     return;
482   setState(YACS::TOLOAD);
483
484   // request loading for all nodes connected to this one by datastream link
485   // Be careful that nodes can be connected in a loop. Put first this node in TOLOAD state to break the loop
486   std::list<OutputDataStreamPort *>::iterator iter;
487   for(iter = _setOfOutputDataStreamPort.begin(); iter != _setOfOutputDataStreamPort.end(); iter++)
488     {
489       OutputDataStreamPort *port=(OutputDataStreamPort *)*iter;
490       std::set<InPort *> ports=port->edSetInPort();
491       std::set<InPort *>::iterator iterout;
492       for(iterout=ports.begin();iterout != ports.end(); iterout++)
493         {
494           Node* node= (*iterout)->getNode();
495           node->ensureLoading();
496         }
497     }
498   /*
499     */
500 }