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