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