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