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