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