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