Salome HOME
Ready to update Executor to take into account of the new type of containers.
[modules/yacs.git] / src / engine / ElementaryNode.cxx
1 // Copyright (C) 2006-2014  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 "ElementaryNode.hxx"
21 #include "Runtime.hxx"
22 #include "InputPort.hxx"
23 #include "OutputPort.hxx"
24 #include "ComposedNode.hxx"
25 #include "InputDataStreamPort.hxx"
26 #include "OutputDataStreamPort.hxx"
27 #include "Visitor.hxx"
28 #include "Proc.hxx"
29 #include "Container.hxx"
30 #include <iostream>
31 #include <sstream>
32
33 //#define _DEVDEBUG_
34 #include "YacsTrace.hxx"
35
36 using namespace YACS::ENGINE;
37 using namespace std;
38
39 /*! \class YACS::ENGINE::ElementaryNode
40  *  \brief Base class for all calculation nodes.
41  *
42  * This is an abstract class that must be specialized.
43  *
44  *  \ingroup Nodes
45  */
46
47 ElementaryNode::ElementaryNode(const std::string& name):
48   Node(name),
49   _createDatastreamPorts(false),
50   _multi_port_node(false)
51 {
52 }
53
54 ElementaryNode::ElementaryNode(const ElementaryNode& other, ComposedNode *father):Node(other,father)
55 {
56   _createDatastreamPorts = other._createDatastreamPorts;
57   _multi_port_node = other._multi_port_node;
58   for(list<InputPort *>::const_iterator iter1=other._setOfInputPort.begin();iter1!=other._setOfInputPort.end();iter1++)
59     _setOfInputPort.push_back((InputPort *)(*iter1)->clone(this));
60   for(list<OutputPort *>::const_iterator iter2=other._setOfOutputPort.begin();iter2!=other._setOfOutputPort.end();iter2++)
61     _setOfOutputPort.push_back((OutputPort *)(*iter2)->clone(this));
62   for(list<InputDataStreamPort *>::const_iterator iter3=other._setOfInputDataStreamPort.begin();iter3!=other._setOfInputDataStreamPort.end();iter3++)
63     _setOfInputDataStreamPort.push_back((InputDataStreamPort *)(*iter3)->clone(this));
64   for(list<OutputDataStreamPort *>::const_iterator iter4=other._setOfOutputDataStreamPort.begin();iter4!=other._setOfOutputDataStreamPort.end();iter4++)
65     _setOfOutputDataStreamPort.push_back((OutputDataStreamPort *)(*iter4)->clone(this));
66 }
67
68 void ElementaryNode::performDuplicationOfPlacement(const Node& other)
69 {
70 }
71
72 ElementaryNode::~ElementaryNode()
73 {
74   for(list<InputPort *>::iterator iter1=_setOfInputPort.begin();iter1!=_setOfInputPort.end();iter1++)
75     delete *iter1;
76   for(list<OutputPort *>::iterator iter2=_setOfOutputPort.begin();iter2!=_setOfOutputPort.end();iter2++)
77     delete *iter2;
78   for(list<InputDataStreamPort *>::iterator iter3=_setOfInputDataStreamPort.begin();iter3!=_setOfInputDataStreamPort.end();iter3++)
79     delete *iter3;
80   for(list<OutputDataStreamPort *>::iterator iter4=_setOfOutputDataStreamPort.begin();iter4!=_setOfOutputDataStreamPort.end();iter4++)
81     delete *iter4;
82 }
83
84 void ElementaryNode::init(bool start)
85 {
86   DEBTRACE("ElementaryNode::init " << getName() << " " << start << " " << _state);
87
88   for(list<OutputPort *>::iterator iter=_setOfOutputPort.begin();iter!=_setOfOutputPort.end();iter++)
89     (*iter)->exInit();
90   for(list<InputPort *>::iterator iter2=_setOfInputPort.begin();iter2!=_setOfInputPort.end();iter2++)
91     (*iter2)->exInit(start);
92   _inGate.exReset();
93   if(_state == YACS::DISABLED)
94     {
95       exDisabledState(); // to refresh propagation of DISABLED state
96       return;
97     }
98   if(start) //complete initialization
99     setState(YACS::READY);
100   else if(_state > YACS::LOADED)//partial initialization (inside a loop)
101     setState(YACS::TORECONNECT);
102 }
103
104 bool ElementaryNode::isDeployable() const
105 {
106   return false;
107 }
108
109 ComponentInstance *ElementaryNode::getComponent()
110 {
111   return 0;
112 }
113
114 const ComponentInstance *ElementaryNode::getComponent() const
115 {
116   return 0;
117 }
118
119 Container *ElementaryNode::getContainer()
120 {
121   return 0;
122 }
123
124 YACS::StatesForNode ElementaryNode::getState() const
125 {
126   return Node::getState();
127 }
128
129 void ElementaryNode::exUpdateState()
130 {
131   DEBTRACE("ElementaryNode::exUpdateState: " << getName() << " " << _state );
132   if(_state==YACS::DISABLED)return;
133   if(_inGate.exIsReady())
134     if(areAllInputPortsValid())
135       {
136         if(_state == YACS::READY)
137           ensureLoading();
138         else if(_state == YACS::LOADED)
139           setState(YACS::TOACTIVATE);
140       }
141     else
142       {
143         string what("ElementaryNode::exUpdateState : Invalid graph given : Node with name \"");
144         what+=_name; what+="\" ready to run whereas some inputports are not set correctly\nCheck coherence DF/CF";
145         setState(YACS::INTERNALERR);
146         _errorDetails=what;
147         throw Exception(what);
148       }
149 }
150
151 int ElementaryNode::getNumberOfInputPorts() const
152 {
153   return _setOfInputPort.size();
154 }
155
156 int ElementaryNode::getNumberOfOutputPorts() const
157 {
158   return _setOfOutputPort.size();
159 }
160
161 InputPort *ElementaryNode::getInputPort(const std::string& name) const throw(YACS::Exception)
162 {
163   try {
164     return Node::getInputPort(name);
165   }
166   catch(Exception& e) {}
167   return getPort<InputPort>(name,_setOfInputPort);
168 }
169
170 OutputPort *ElementaryNode::getOutputPort(const std::string& name) const throw(YACS::Exception)
171 {
172   return getPort<OutputPort>(name,_setOfOutputPort);
173 }
174
175 std::set<OutPort *> ElementaryNode::getAllOutPortsLeavingCurrentScope() const
176 {
177   set<OutPort *> ret;
178   list<OutPort *> temp=getSetOfOutPort();
179   for(list<OutPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
180     {
181       set<InPort *> temp2=(*iter2)->edSetInPort();
182       if(temp2.size()!=0)
183         ret.insert(*iter2);
184     }
185   return ret;
186 }
187
188 std::set<InPort *> ElementaryNode::getAllInPortsComingFromOutsideOfCurrentScope() const
189 {
190   set<InPort *> ret;
191   list<InPort *> temp=getSetOfInPort();
192   for(list<InPort *>::iterator iter2=temp.begin();iter2!=temp.end();iter2++)
193     {
194       set<OutPort *> temp2=(*iter2)->edSetOutPort();
195       if(temp2.size()!=0)
196         ret.insert(*iter2);
197     }
198   return ret;
199 }
200
201 std::vector< std::pair<OutPort *, InPort *> > ElementaryNode::getSetOfLinksLeavingCurrentScope() const
202 {
203   vector< pair<OutPort *, InPort *> > ret;
204   std::set<OutPort *> ports=getAllOutPortsLeavingCurrentScope();
205   for(set<OutPort *>::iterator iter2=ports.begin();iter2!=ports.end();iter2++)
206     {
207       set<InPort *> temp2=(*iter2)->edSetInPort();
208       for(set<InPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
209         ret.push_back(pair<OutPort *, InPort *>(*iter2,*iter3));
210     }
211   return ret;
212 }
213
214 std::vector< std::pair<InPort *, OutPort *> > ElementaryNode::getSetOfLinksComingInCurrentScope() const
215 {
216   vector< pair<InPort *, OutPort *> > ret;
217   set<InPort *> ports=getAllInPortsComingFromOutsideOfCurrentScope();
218   for(set<InPort *>::iterator iter2=ports.begin();iter2!=ports.end();iter2++)
219     {
220       set<OutPort *> temp2=(*iter2)->edSetOutPort();
221       for(set<OutPort *>::iterator iter3=temp2.begin();iter3!=temp2.end();iter3++)
222         {
223           std::set<OutPort *> trueOutPorts;
224           (*iter3)->getAllRepresented(trueOutPorts);
225           for(std::set<OutPort *>::iterator iter4=trueOutPorts.begin();iter4!=trueOutPorts.end();++iter4)
226             ret.push_back(pair<InPort *, OutPort *>(*iter2,*iter4));
227         }
228     }
229   return ret;
230 }
231
232 InputDataStreamPort *ElementaryNode::getInputDataStreamPort(const std::string& name) const throw(YACS::Exception)
233 {
234   return getPort<InputDataStreamPort>(name,_setOfInputDataStreamPort);
235 }
236
237 OutputDataStreamPort *ElementaryNode::getOutputDataStreamPort(const std::string& name) const throw(YACS::Exception)
238 {
239   return getPort<OutputDataStreamPort>(name,_setOfOutputDataStreamPort);
240 }
241
242 void ElementaryNode::edDisconnectAllLinksWithMe()
243 {
244   //CF
245   Node::edDisconnectAllLinksWithMe();
246   //Leaving part
247   // - DF
248   for(list<InputPort *>::iterator iter=_setOfInputPort.begin();iter!=_setOfInputPort.end();iter++)
249     (*iter)->edRemoveAllLinksLinkedWithMe();
250   // - DS
251   for(list<InputDataStreamPort *>::iterator iter2=_setOfInputDataStreamPort.begin();iter2!=_setOfInputDataStreamPort.end();iter2++)
252     (*iter2)->edRemoveAllLinksLinkedWithMe();
253   //Arriving part
254   // - DF
255   for(list<OutputPort *>::iterator iter=_setOfOutputPort.begin();iter!=_setOfOutputPort.end();iter++)
256     (*iter)->edRemoveAllLinksLinkedWithMe();
257   // - DS
258   for(list<OutputDataStreamPort *>::iterator iter2=_setOfOutputDataStreamPort.begin();iter2!=_setOfOutputDataStreamPort.end();iter2++)
259     (*iter2)->edRemoveAllLinksLinkedWithMe();
260 }
261
262 /**
263  * checks if all input ports contains a valid data. Used at execution to change the state of the node
264  * for activation.
265  */
266
267 bool ElementaryNode::areAllInputPortsValid() const
268 {
269   bool ret=true;
270   for(list<InputPort *>::const_iterator iter=_setOfInputPort.begin();iter!=_setOfInputPort.end();iter++)
271     {
272       ret=!(*iter)->isEmpty();
273       if (!ret) break;
274     }
275   return ret;
276 }
277
278 /*
279   This method is used by the "multi" property of ElementaryNode to create
280   to create duplicated input and ouput datastream ports.
281 */
282 void
283 ElementaryNode::createMultiDatastreamPorts()
284 {
285   if (!_createDatastreamPorts)
286   {
287     _createDatastreamPorts = true;
288     for(list<InputDataStreamPort *>::const_iterator iter3 = _setOfInputDataStreamPort.begin(); iter3!=_setOfInputDataStreamPort.end();iter3++)
289     {
290       InputDataStreamPort * port = *iter3;
291       std::string port_name = port->getName();
292       std::map<std::string,std::string>::iterator it=_propertyMap.find(port_name);
293       int multi = 1;
294       if(it != _propertyMap.end())
295       {
296         std::string multi_str = it->second;
297         std::istringstream iss(multi_str);
298         if (!(iss >> multi))
299           throw Exception("Property multi port should be set with a stringified int not an: " + multi_str);
300       }
301
302       if (multi > 1)
303       {
304         addDatastreamPortToInitMultiService(port_name, multi);
305         // Change name of first port
306         port->setName(port_name + "_0");
307         for (int i = 2; i <= multi; i++)
308         {
309           InputDataStreamPort * new_port = port->clone(this);
310           std::ostringstream number;
311           number << i-1;
312           new_port->setName(port_name + "_" + number.str());
313           _setOfInputDataStreamPort.push_back(new_port);
314           _multi_port_node = true;
315         }
316       }
317     }
318     for(list<OutputDataStreamPort *>::const_iterator iter4 = _setOfOutputDataStreamPort.begin(); iter4!=_setOfOutputDataStreamPort.end();iter4++)
319     {
320       OutputDataStreamPort * port = *iter4;
321       std::string port_name = port->getName();
322       std::map<std::string,std::string>::iterator it=_propertyMap.find(port_name);
323       int multi = 1;
324       if(it != _propertyMap.end())
325       {
326         std::string multi_str = it->second;
327         std::istringstream iss(multi_str);
328         if (!(iss >> multi))
329           throw Exception("Property multi port should be set with a stringified int not an: " + multi_str);
330       }
331
332       if (multi > 1)
333       {
334         addDatastreamPortToInitMultiService(port_name, multi);
335         // Change name of first port
336         port->setName(port_name + "_0");
337         for (int i = 2; i <= multi; i++)
338         {
339           OutputDataStreamPort * new_port = port->clone(this);
340           std::ostringstream number;
341           number << i-1;
342           new_port->setName(port_name + "_" + number.str());
343           _setOfOutputDataStreamPort.push_back(new_port);
344           _multi_port_node = true;
345         }
346       }
347     }
348   }
349 }
350
351 /**
352  * add this node task to a given set of ready tasks, if this task is ready to activate
353  */
354
355 void ElementaryNode::getReadyTasks(std::vector<Task *>& tasks)
356 {
357   DEBTRACE("ElementaryNode::getReadyTasks: " << getName() << " " << _state);
358
359   int multi = 1;
360   std::map<std::string,std::string>::iterator it=_propertyMap.find("multi");
361   if(it != _propertyMap.end())
362   {
363     std::string multi_str = it->second;
364     std::istringstream iss(multi_str);
365     if (!(iss >> multi))
366       throw Exception("Property multi should be set with a stringified int not an: " + multi_str);
367   }
368
369   if(_state==YACS::TOACTIVATE || _state==YACS::TOLOAD || _state==YACS::TORECONNECT)
370   {
371     if (multi == 1)
372     {
373       std::map<std::string,std::string>::iterator it=_propertyMap.find("multi_working_dir");
374       if(it != _propertyMap.end())
375       {
376         std::string working_dir_base = it->second;
377         std::ostringstream working_dir_stream;
378         working_dir_stream << working_dir_base;
379         working_dir_stream << 1;
380         this->getContainer()->setProperty("workingdir", working_dir_stream.str());
381       }
382       tasks.push_back(this);
383     }
384     else
385     {
386
387       // Check output port -> cannot clone an Elementary Node with Output Ports connected
388       std::list<OutputPort *>::iterator it_output = _setOfOutputPort.begin();
389       for (;it_output != _setOfOutputPort.end(); it_output++)
390       {
391         if ((*it_output)->isConnected())
392         {
393           throw Exception("Property multi cannot be set on nodes with dataflow output ports connected");
394         }
395       }
396
397       // Add my instance
398       std::map<std::string,std::string>::iterator it=_propertyMap.find("multi_working_dir");
399       if(it != _propertyMap.end())
400       {
401         std::string working_dir_base = it->second;
402         std::ostringstream working_dir_stream;
403         working_dir_stream << working_dir_base;
404         working_dir_stream << 1;
405         this->getContainer()->setProperty("workingdir", working_dir_stream.str());
406       }
407       tasks.push_back(this);
408
409       // Step 1: Create clones
410       for (int i = 1; i < multi; i++)
411       {
412         // Clone
413         YACS::ENGINE::ElementaryNode * new_node = static_cast<YACS::ENGINE::ElementaryNode *>(clone(_father, false));
414         new_node->createMultiDatastreamPorts();
415
416         // Change name
417         std::string iname;
418         std::stringstream inamess;
419         inamess << getName() << "_" << i;
420         iname=inamess.str();
421         DEBTRACE("Create clone "<< iname << " of node " << getName());
422         new_node->setName(iname);
423
424         // For each input port connect it with the original output port
425         std::list<InputPort *> clone_list_inputPorts = new_node->getSetOfInputPort();
426         for(list<InputPort *>::const_iterator iter1=clone_list_inputPorts.begin(); iter1!=clone_list_inputPorts.end(); iter1++)
427         {
428           std::string input_port_name = (*iter1)->getName();
429           // Get Port Name in master node
430           InputPort * master_port = getInputPort(input_port_name);
431           for (std::set<OutPort *>::const_iterator itt=master_port->_backLinks.begin(); itt!=master_port->_backLinks.end();itt++)
432           {
433             // Connect dataflow
434             getProc()->edAddDFLink((*itt),(*iter1));
435           }
436         }
437
438         // InputDataStreamPort connections
439         std::list<InputDataStreamPort *> clone_list_inputDatastreamPorts = new_node->getSetOfInputDataStreamPort();
440         for(list<InputDataStreamPort *>::iterator iter = clone_list_inputDatastreamPorts.begin(); iter != clone_list_inputDatastreamPorts.end(); iter++)
441         {
442           std::string port_name = (*iter)->getName();
443           InputDataStreamPort * orig_port = getInputDataStreamPort(port_name);
444
445           std::set<OutputDataStreamPort *> connected_ports = orig_port->getConnectedOutputDataStreamPort();
446
447           // Create datastream ports if not created
448           std::set<OutputDataStreamPort *>::const_iterator iter3;
449           for(iter3=connected_ports.begin();iter3!=connected_ports.end();iter3++)
450           {
451             ElementaryNode * node = (ElementaryNode *) (*iter3)->getNode();
452             node->createMultiDatastreamPorts();
453
454             std::string good_port_name;
455             std::stringstream temp_name;
456             std::string out_name = (*iter3)->getName();
457             out_name.erase(out_name.end()-1);
458             temp_name << out_name << i;
459             good_port_name = temp_name.str();
460             getProc()->edAddLink(node->getOutputDataStreamPort(good_port_name), (*iter));
461           }
462         }
463
464         // OutputDataStreamPort connections
465         std::list<OutputDataStreamPort *> clone_list_outputDatastreamPorts = new_node->getSetOfOutputDataStreamPort();
466         for(list<OutputDataStreamPort *>::iterator iter = clone_list_outputDatastreamPorts.begin(); iter != clone_list_outputDatastreamPorts.end(); iter++)
467         {
468           std::string port_name = (*iter)->getName();
469           OutputDataStreamPort * orig_port = getOutputDataStreamPort(port_name);
470           std::set<InputDataStreamPort *> dest_input_port = orig_port->_setOfInputDataStreamPort;
471           for(set<InputDataStreamPort *>::iterator dest_port = dest_input_port.begin(); dest_port != dest_input_port.end(); dest_port++)
472           {
473             ElementaryNode * dest_node = (ElementaryNode *)(*dest_port)->getNode();
474             // Add InputPort to dest node
475             dest_node->createMultiDatastreamPorts();
476
477             std::string good_port_name;
478             std::stringstream temp_name;
479             std::string in_name = (*dest_port)->getName();
480             in_name.erase(in_name.end()-1);
481             temp_name << in_name << i;
482             good_port_name = temp_name.str();
483             getProc()->edAddLink((*iter), dest_node->getInputDataStreamPort(good_port_name));
484           }
485         }
486
487         // Init node
488         new_node->init(false);
489         new_node->exUpdateState();
490
491         // Set Control Link to done
492         std::list<OutGate *> clone_cl_back = new_node->getInGate()->getBackLinks();
493         for(std::list<OutGate *>::const_iterator iter=clone_cl_back.begin(); iter!=clone_cl_back.end(); iter++)
494           new_node->getInGate()->exNotifyFromPrecursor((*iter));
495
496         // Add clone
497         std::map<std::string,std::string>::iterator it=_propertyMap.find("multi_working_dir");
498         if(it != _propertyMap.end())
499         {
500           std::string working_dir_base = it->second;
501           std::ostringstream working_dir_stream;
502           working_dir_stream << working_dir_base;
503           working_dir_stream << i+1;
504           new_node->getContainer()->setProperty("workingdir", working_dir_stream.str());
505         }
506         tasks.push_back(new_node);
507       }
508     }
509   }
510 }
511
512 /**
513  * remove port from node at edition. Ports are typed.
514  */
515
516 void ElementaryNode::edRemovePort(Port *port) throw(YACS::Exception)
517 {
518   DEBTRACE("ElementaryNode::edRemovePort ");
519   if(port->getNode()!=this)
520     throw Exception("ElementaryNode::edRemovePort : Port is not held by this node");
521   if(InputPort *p=dynamic_cast<InputPort *>(port))
522     edRemovePortTypedFromSet<InputPort>(p,_setOfInputPort);
523   else if(OutputPort *p=dynamic_cast<OutputPort *>(port))
524     edRemovePortTypedFromSet<OutputPort>(p,_setOfOutputPort);
525   else if(InputDataStreamPort *p=dynamic_cast<InputDataStreamPort *>(port))
526     edRemovePortTypedFromSet<InputDataStreamPort>(p,_setOfInputDataStreamPort);
527   else if(OutputDataStreamPort *p=dynamic_cast<OutputDataStreamPort *>(port))
528     edRemovePortTypedFromSet<OutputDataStreamPort>(p,_setOfOutputDataStreamPort);
529   else
530     throw Exception("ElementaryNode::edRemovePort : unknown port type");
531   delete port;
532   modified();
533 }
534
535 /**
536  * @return a set with only this node. (Same method in composed nodes)
537  */
538
539 list<ElementaryNode *> ElementaryNode::getRecursiveConstituents() const
540 {
541   list<ElementaryNode *> ret;
542   ret.push_back((ElementaryNode *)this);
543   return ret;
544 }
545
546 Node *ElementaryNode::getChildByName(const std::string& name) const throw(YACS::Exception)
547 {
548   string what("ElementaryNode does not agregate any nodes particullary node with name "); what+=name;
549   throw Exception(what);
550 }
551
552 void ElementaryNode::checkBasicConsistency() const throw(YACS::Exception)
553 {
554   DEBTRACE("ElementaryNode::checkBasicConsistency");
555   list<InputPort *>::const_iterator iter;
556   for(iter=_setOfInputPort.begin();iter!=_setOfInputPort.end();iter++)
557     (*iter)->checkBasicConsistency();  
558 }
559
560 ComposedNode *ElementaryNode::getDynClonerIfExists(const ComposedNode *levelToStop) const
561 {
562   for(ComposedNode *iter=_father;iter!=levelToStop && iter!=0; iter=iter->_father)
563     if(!iter->isPlacementPredictableB4Run())
564       return iter;
565   return 0;
566 }
567
568 InputPort *ElementaryNode::createInputPort(const std::string& inputPortName, TypeCode* type)
569 {
570   return getRuntime()->createInputPort(inputPortName, _implementation, this, type);
571 }
572
573 /**
574  * the input port is also published recursively in ancestors because it may be visible from everywhere.
575  * WARNING: CHECK CASE OF BLOC: ONLY INPUT PORTS NOT INTERNALLY CONNECTED MUST BE VISIBLE.
576  */
577
578 InputPort *ElementaryNode::edAddInputPort(const std::string& inputPortName, TypeCode* type) throw(YACS::Exception)
579 {
580
581   // Cannot create an InputPort defined with InPropertyPort name.
582   if (inputPortName == "__InPropertyPort__Node__YACS_")
583   {
584     string what("ElementaryNode::edAddInputPort: it is forbidden to add an InputPort with the name __InPropertyPort__Node__YACS_\"");
585     throw Exception(what);
586   }
587
588   InputPort *ret = 0;
589   if (edCheckAddPort<InputPort, TypeCode*>(inputPortName,_setOfInputPort,type))
590     {
591       ret = createInputPort(inputPortName, type);
592       _setOfInputPort.push_back(ret);
593       modified();
594       /*
595       ComposedNode *iter=_father;
596       while(iter)
597         iter=iter->_father;
598         */
599     }
600   return ret;
601 }
602
603 void ElementaryNode::edOrderInputPorts(const std::list<InputPort*>& ports)
604 {
605   std::set<InputPort *> s1;
606   std::set<InputPort *> s2;
607   for(list<InputPort *>::const_iterator it=_setOfInputPort.begin();it != _setOfInputPort.end();it++)
608     s1.insert(*it);
609   for(list<InputPort *>::const_iterator it=ports.begin();it != ports.end();it++)
610     s2.insert(*it);
611
612   if(s1 != s2)
613     throw Exception("ElementaryNode::edOrderInputPorts : port list must contain same ports as existing ones");
614
615   _setOfInputPort.clear();
616   for(list<InputPort *>::const_iterator it=ports.begin();it != ports.end();it++)
617     _setOfInputPort.push_back(*it);
618 }
619
620 void ElementaryNode::edOrderOutputPorts(const std::list<OutputPort*>& ports)
621 {
622   std::set<OutputPort *> s1;
623   std::set<OutputPort *> s2;
624   for(list<OutputPort *>::const_iterator it=_setOfOutputPort.begin();it != _setOfOutputPort.end();it++)
625     s1.insert(*it);
626   for(list<OutputPort *>::const_iterator it=ports.begin();it != ports.end();it++)
627     s2.insert(*it);
628
629   if(s1 != s2)
630     throw Exception("ElementaryNode::edOrderOutputPorts : port list must contain same ports as existing ones");
631
632   _setOfOutputPort.clear();
633   for(list<OutputPort *>::const_iterator it=ports.begin();it != ports.end();it++)
634     _setOfOutputPort.push_back(*it);
635 }
636
637 OutputPort *ElementaryNode::createOutputPort(const std::string& outputPortName, TypeCode* type)
638 {
639   return getRuntime()->createOutputPort(outputPortName, _implementation, this, type);
640 }
641
642 /**
643  * TO SOLVE : The output port is not published in father. Father must create an output port.
644  * for now, publication is done the same way as input ports
645  */ 
646
647 OutputPort *ElementaryNode::edAddOutputPort(const std::string& outputPortName, TypeCode* type) throw(YACS::Exception)
648 {
649   OutputPort *ret =0;
650   if (edCheckAddPort<OutputPort, TypeCode*>(outputPortName,_setOfOutputPort,type))
651     {
652       ret = createOutputPort(outputPortName, type);
653       _setOfOutputPort.push_back(ret);
654       modified();
655       /*
656       ComposedNode *iter=_father;
657       while(iter)
658         iter=iter->_father;
659         */
660     }
661   return ret;
662 }
663
664 InputDataStreamPort *ElementaryNode::createInputDataStreamPort(const std::string& inputPortDSName, TypeCode* type)
665 {
666   return getRuntime()->createInputDataStreamPort(inputPortDSName, this, type);
667 }
668
669 InputDataStreamPort *ElementaryNode::edAddInputDataStreamPort(const std::string& inputPortDSName, TypeCode* type) throw(YACS::Exception)
670 {
671   InputDataStreamPort *ret = 0;
672   if (edCheckAddPort<InputDataStreamPort, TypeCode*>(inputPortDSName,_setOfInputDataStreamPort,type))
673     {
674       ret = createInputDataStreamPort(inputPortDSName, type);
675       _setOfInputDataStreamPort.push_back(ret);
676       modified();
677     }
678   return ret;
679 }
680
681 OutputDataStreamPort *ElementaryNode::createOutputDataStreamPort(const std::string& outputPortDSName, TypeCode* type)
682 {
683   return getRuntime()->createOutputDataStreamPort(outputPortDSName, this, type);
684 }
685
686 OutputDataStreamPort *ElementaryNode::edAddOutputDataStreamPort(const std::string& outputPortDSName, TypeCode* type) throw(YACS::Exception)
687 {
688   OutputDataStreamPort *ret = 0;
689   if (edCheckAddPort<OutputDataStreamPort, TypeCode*>(outputPortDSName,_setOfOutputDataStreamPort,type))
690     {
691       ret = createOutputDataStreamPort(outputPortDSName, type);
692       _setOfOutputDataStreamPort.push_back(ret);
693       modified();
694     }
695   return ret;
696 }
697
698 /**
699  * get the input port name used by the current node (see composed nodes)
700  */
701
702 string ElementaryNode::getInPortName(const InPort * inPort) const throw(YACS::Exception)
703 {
704   Node *node = inPort->getNode();
705   if ( node != this ) 
706     {
707       string what("InputPort "); what += inPort->getName(); what += " does not belong to node "; what += node->getName();
708       throw Exception(what);
709     }
710   return inPort->getName();
711 }
712
713 string ElementaryNode::getOutPortName(const OutPort *outPort) const throw(YACS::Exception)
714 {
715   Node *node = outPort->getNode();
716   if ( node != this ) 
717     {
718       string what("OutputPort "); what += outPort->getName(); what += " does not belong to node "; what += node->getName();
719       throw Exception(what);
720     }
721   return outPort->getName();
722 }
723
724 void ElementaryNode::begin()
725 {
726   setState(ACTIVATED);
727 }
728
729 bool ElementaryNode::isReady()
730 {
731   return _state==TOACTIVATE;
732 }
733
734 void ElementaryNode::finished()
735 {
736   setState(DONE);
737 }
738 void ElementaryNode::aborted()
739 {
740   setState(ERROR);
741 }
742
743 //! Notify this node that it is loaded
744 /*!
745  * When an elementary node has been loaded 
746  * It is ready to be connected
747  *
748  */
749 void ElementaryNode::loaded()
750 {
751 }
752
753 //! Notify this node that it is connected
754 /*!
755  * When an elementary node has been connected it goes to TOACTIVATE state
756  * It is then ready to be executed
757  *
758  */
759 void ElementaryNode::connected()
760 {
761   if(_inGate.exIsReady())
762     if(areAllInputPortsValid())
763       {
764         setState(TOACTIVATE);
765         return;
766       }
767   setState(LOADED);
768 }
769
770 void ElementaryNode::accept(Visitor *visitor)
771 {
772   visitor->visitElementaryNode(this);
773 }
774
775 //! Give a description of error when node status is ERROR
776 /*!
777  *
778  */
779 std::string ElementaryNode::getErrorDetails()
780 {
781   return _errorDetails;
782 }
783
784 void ElementaryNode::edUpdateState()
785 {
786   DEBTRACE("ElementaryNode::edUpdateState: " << getName());
787   YACS::StatesForNode state=YACS::READY;
788   try
789     {
790       checkBasicConsistency();
791       _errorDetails="";
792     }
793   catch(Exception& e)
794     {
795       state=YACS::INVALID;
796       _errorDetails=e.what();
797     }
798   DEBTRACE("ElementaryNode::edUpdateState: " << _errorDetails);
799   if(state != _state)
800     setState(state);
801   _modified=0;
802 }
803
804 //! Put this node into TOLOAD state when possible
805 /*!
806  * Can be called by another ElementaryNode that is connected to this one by a datastream link
807  * These 2 nodes must be loaded at the same time as they are coupled
808  * It's the other node which requests this node loading
809  */
810 void ElementaryNode::ensureLoading()
811 {
812   DEBTRACE("ElementaryNode::ensureLoading: " << getName());
813   if(_state != YACS::READY)
814     return;
815   setState(YACS::TOLOAD);
816
817   // request loading for all nodes connected to this one by datastream link
818   // Be careful that nodes can be connected in a loop. Put first this node in TOLOAD state to break the loop
819   std::list<OutputDataStreamPort *>::iterator iterout;
820   for(iterout = _setOfOutputDataStreamPort.begin(); iterout != _setOfOutputDataStreamPort.end(); iterout++)
821     {
822       OutputDataStreamPort *port=(OutputDataStreamPort *)*iterout;
823       std::set<InPort *> ports=port->edSetInPort();
824       std::set<InPort *>::iterator iter;
825       for(iter=ports.begin();iter != ports.end(); iter++)
826         {
827           Node* node= (*iter)->getNode();
828           node->ensureLoading();
829         }
830     }
831   std::list<InputDataStreamPort *>::iterator iterin;
832   for(iterin = _setOfInputDataStreamPort.begin(); iterin != _setOfInputDataStreamPort.end(); iterin++)
833     {
834       InputDataStreamPort *port=(InputDataStreamPort *)*iterin;
835       std::set<OutPort *> ports=port->edSetOutPort();
836       std::set<OutPort *>::iterator iter;
837       for(iter=ports.begin();iter != ports.end(); iter++)
838         {
839           Node* node= (*iter)->getNode();
840           node->ensureLoading();
841         }
842     }
843 }
844
845 //! Calls getCoupledNodes for Task interface
846 void ElementaryNode::getCoupledTasks(std::set<Task*>& coupledSet)
847 {
848   getCoupledNodes(coupledSet);
849 }
850
851 //! Put all nodes that are coupled to this node in coupledSet
852 void ElementaryNode::getCoupledNodes(std::set<Task*>& coupledSet)
853 {
854   if(coupledSet.find(this) != coupledSet.end())return;
855
856   coupledSet.insert(this);
857
858   std::list<OutputDataStreamPort *>::iterator iterout;
859   for(iterout = _setOfOutputDataStreamPort.begin(); iterout != _setOfOutputDataStreamPort.end(); iterout++)
860     {
861       OutputDataStreamPort *port=(OutputDataStreamPort *)*iterout;
862       std::set<InPort *> ports=port->edSetInPort();
863       std::set<InPort *>::iterator iter;
864       for(iter=ports.begin();iter != ports.end(); iter++)
865         {
866           Node* node= (*iter)->getNode();
867           node->getCoupledNodes(coupledSet);
868         }
869     }
870 }
871