Salome HOME
PR: merge from BR_DATACONV_PR tag "mergeto_trunk_25oct06"
[modules/yacs.git] / src / engine / ComposedNode.cxx
1 #include "ComposedNode.hxx"
2 #include "InputPort.hxx"
3 #include "OutputPort.hxx"
4 #include "ElementaryNode.hxx"
5
6 #include <set>
7 #include <string>
8
9 using namespace YACS::ENGINE;
10 using namespace std;
11
12 ComposedNode::ComposedNode(const string& name):Node(name)
13 {
14 }
15
16 /**
17  * A COMMENTER DAVANTAGE
18  * @note : Runtime called method. Overloads the Scheduler::notifyFrom abstract method.
19  * Typically Called in Executor (in a parallel thread or not) by the Task 'task'
20  * to inform the scheduler that an event coded 'event' (in Executor static const var) happened.
21  * Contrary to updateStateFrom several level may exist between 'sender' and 'this'.
22  *
23  */
24 void ComposedNode::notifyFrom(const Task *sender, //* I : task emitting event
25                               YACS::Event event   //* I : event emitted
26                               )
27 {
28   ElementaryNode *taskTyped=dynamic_cast<ElementaryNode *>((Task *)sender);
29   //ASSERT(taskTyped != 0)
30   YACS::Event curEvent=event;
31   Node *lminus1LevelNode=taskTyped;
32   ComposedNode *curLevelNode=taskTyped->_father;
33   curEvent=curLevelNode->updateStateFrom(lminus1LevelNode,curEvent);
34   while(curEvent!=YACS::NOEVENT && curLevelNode!=this)
35     {
36       lminus1LevelNode=curLevelNode;
37       curLevelNode=curLevelNode->_father;
38       curEvent=curLevelNode->updateStateFrom(lminus1LevelNode,curEvent);
39     }
40 }
41
42 /**
43  *  Add a dataflow link.
44  *  Precondition : 'start' AND 'end' are in/outputPort contained in a node in descendance of 'this'.
45  * @exception incompatibility between input and output (type), or 'start'/'end' is/are NOT in/outputPort
46  *            contained in a node in descendance of 'this', or a multiple link to an input not supporting it.
47  * @return    true if a new link has been created, false otherwise.
48  */
49
50 bool ComposedNode::edAddLink(OutputPort *start, InputPort *end) throw(Exception)
51 {
52   ComposedNode* lwstCmnAnctr=getLowestCommonAncestor(start->getNode(),end->getNode());
53   set<ComposedNode *> allAscendanceOfNodeStart=start->getNode()->getAllAscendanceOf(lwstCmnAnctr);
54   set<ComposedNode *> allAscendanceOfNodeEnd=end->getNode()->getAllAscendanceOf(lwstCmnAnctr);
55   checkInMyDescendance(lwstCmnAnctr);
56   ComposedNode *iterS=start->getNode()->_father;
57
58   OutPort *currentPortO=start;
59   while(iterS!=lwstCmnAnctr)
60     {
61       currentPortO=iterS->buildDelegateOf(currentPortO, allAscendanceOfNodeStart);
62       iterS=iterS->_father;
63     }
64   iterS=end->getNode()->_father;
65
66   InPort *currentPortI=end;
67   while(iterS!=lwstCmnAnctr)
68     {
69       currentPortI=iterS->buildDelegateOf(currentPortI, allAscendanceOfNodeEnd);
70       iterS=iterS->_father;
71     }
72
73   bool linkDone = currentPortO->addInPort(currentPortI);
74   if (linkDone)
75     {
76       ComposedNode *iter=end->getNode()->_father;
77       while(iter)
78         {
79           iter->unpublishInputPort(end);
80           iter=iter->_father;
81         }
82     }
83
84   return linkDone;
85 }
86
87 /**
88  * @note : Add a controlflow link.
89  *          Precondition : 'start' AND 'end' are in/outGate contained in a node in DIRECT descendance of 'this'.
90  * @exception : If a cycle has been detected, or incompatibility between input and output, or 'start'/'end' is/are NOT in/outputPort
91  *               contained in a node in descendance of 'this', or a mutilple link to an input not supporting it.
92  * @return : true if a new link has been created, false otherwise. 
93  */
94 bool ComposedNode::edAddLink(OutGate *start, InGate *end) throw(Exception)
95 {
96   ComposedNode* father=checkHavingCommonFather(start->getNode(),end->getNode());
97   if(father!=this)
98     {
99       checkInMyDescendance(father);
100       return father->edAddLink(start,end);
101     }
102   bool ret=start->edAddInGate(end);
103   if(ret)
104     checkNoCyclePassingThrough(end->getNode());
105   return ret;
106 }
107
108 bool ComposedNode::edAddCFLink(Node *nodeS, Node *nodeE) throw(Exception)
109 {
110   ComposedNode* father=checkHavingCommonFather(nodeS,nodeE);
111   if(father!=this)
112     {
113       checkInMyDescendance(father);
114       return father->edAddLink(nodeS->getOutGate(),nodeE->getInGate());
115     }
116   bool ret=nodeS->getOutGate()->edAddInGate(nodeE->getInGate());
117   if(ret)
118     checkNoCyclePassingThrough(nodeE);
119   return ret;
120 }
121
122 /**
123  * Remove a dataflow link.
124  * Precondition : 'start' AND 'end' are in/outputPort contained in a node in descendance of 'this'.
125  * @exception The specified link does not exist.
126  *            The content of Exception is different in accordance with the link from 'start' to 'end' implies DF/DS gateway.
127  */
128
129 void ComposedNode::edRemoveLink(OutputPort *start, InputPort *end) throw(Exception)
130 {
131   ComposedNode* lwstCmnAnctr=getLowestCommonAncestor(start->getNode(),end->getNode());
132   checkInMyDescendance(lwstCmnAnctr);
133   set<ComposedNode *> allAscendanceOfNodeStart=start->getNode()->getAllAscendanceOf(lwstCmnAnctr);
134   set<ComposedNode *> allAscendanceOfNodeEnd=end->getNode()->getAllAscendanceOf(lwstCmnAnctr);
135
136   // --- Part of test if the link from 'start' to 'end' really exist particulary all eventually intermediate ports created
137
138   ComposedNode *iterS=start->getNode()->_father;
139   OutPort *currentPortO=start;
140   while(iterS!=lwstCmnAnctr)
141     {
142       currentPortO=iterS->getDelegateOf(currentPortO, allAscendanceOfNodeEnd);
143       iterS=iterS->_father;
144     }
145
146   iterS=end->getNode()->_father;
147   InPort *currentPortI=end;
148   while(iterS!=lwstCmnAnctr)
149     {
150       currentPortI=iterS->getDelegateOf(currentPortI, allAscendanceOfNodeStart);
151       iterS=iterS->_father;
152     }
153
154   // --- End of test for evt intermediate ports created
155
156   currentPortO->removeInPort(currentPortI);
157
158   // --- Performing deletion of intermediate ports
159
160   iterS=start->getNode()->_father;
161   currentPortO=start; currentPortI=end;
162   while(iterS!=lwstCmnAnctr)
163     {
164       currentPortO=iterS->releaseDelegateOf(currentPortO, allAscendanceOfNodeEnd);
165       iterS=iterS->_father;
166     }
167
168   iterS=end->getNode()->_father;
169   while(iterS!=lwstCmnAnctr)
170     {
171       currentPortI=iterS->releaseDelegateOf(currentPortI, allAscendanceOfNodeStart);
172       iterS=iterS->_father;
173     }
174
175   // --- publish inputPort in ancestors
176
177   ComposedNode *iter=end->getNode()->_father;
178   while(iter)
179     {
180       iter->publishInputPort(end);
181       iter=iter->_father;
182     }
183 }
184
185 void ComposedNode::edRemoveLink(OutGate *start, InGate *end) throw(Exception)
186 {
187   ComposedNode* father=checkHavingCommonFather(start->getNode(),end->getNode());
188   if(father!=this)
189     throw Exception("edRemoveLink : nodes not in direct descendance of this");
190   start->edRemoveInGate(end);
191 }
192
193 void ComposedNode::publishOutputPort(OutputPort *port) throw(Exception)
194 {
195   checkInMyDescendance(port->getNode());
196   _setOfOutputPort.insert(port);
197 }
198
199 void ComposedNode::publishInputPort(InputPort *port)
200 {
201   _setOfInputPort.insert(port);
202 }
203
204 void ComposedNode::unpublishInputPort(InputPort *port)
205 {
206   _setOfInputPort.erase(port);
207 }
208
209
210 ComposedNode *ComposedNode::getRootNode() throw(Exception)
211 {
212   if(!_father)
213     return this;
214   return Node::getRootNode();
215 }
216
217 /**
218  * @note : perform the disconnection of all links under the scope of 'this' connected to an input (dataflow or datastream) of node 'node'.
219  *          This method is quite heavy because the links are stored in one direction.
220  */
221 void ComposedNode::disconnectAllLinksConnectedTo(Node *node)
222 {
223   set<ElementaryNode *> setOfAllNodes=getRecursiveConstituents();
224   for(set<ElementaryNode *>::iterator iter=setOfAllNodes.begin();iter!=setOfAllNodes.end();iter++)
225     (*iter)->disconnectAllLinksConnectedTo(node);
226 }
227
228 /**
229  * @note : Check that 'nodeToTest' is in descendance of 'this' OR equal to 'this'
230  * @exception : If 'nodeToTest' is NOT in descendance of 'this' AND not equal to 'this'
231  */
232 void ComposedNode::checkInMyDescendance(Node *nodeToTest) const throw(Exception)
233 {
234   const char what[]="check failed : node is not in the correct descendance";
235   if(nodeToTest==0)
236     throw Exception(what);
237   if((ComposedNode *)nodeToTest==this)
238     return;
239   ComposedNode *iter=nodeToTest->_father;
240   while(iter!=0 && iter!=this)
241     iter=iter->_father;
242   if(iter==0)
243     throw Exception(what);
244 }
245
246 /**
247  * 
248  * @note : Retrieves the lowest common ancestor of 'node1' AND 'node2'. If 'node1' AND 'node2' are equals and are instance of ComposedNode 
249  *          the father of 'node1' is returned.
250  * @exception : 'node1' and 'node2' does not share the same genealogy.
251  * @return : The lowest common ancestor if it exists.
252  *
253  */
254 ComposedNode *ComposedNode::getLowestCommonAncestor(Node *node1, Node *node2) throw(Exception)
255 {
256   const char what[]="2 nodes does not share the same genealogy";
257   if(node1==0 || node2==0)
258     throw Exception(what);
259   ComposedNode *temp=node1->_father;
260   set<ComposedNode *> s;
261   while(temp)
262     {
263       s.insert(temp);
264       temp=temp->_father;
265     }
266   //
267   temp=node2->_father;
268   set<ComposedNode *>::iterator iter=s.find(temp);
269   while(temp && iter==s.end())
270     {
271       iter=s.find(temp);
272       temp=temp->_father;
273     }
274   if(iter==s.end())
275     throw Exception(what);
276   return *iter;
277 }
278
279 /**
280  * get the input port name used by the current node, reursively built with children names.
281  */
282
283 const string ComposedNode::getInputPortName(const InputPort * inputPort) throw (Exception)
284 {
285   Node *node = inputPort->getNode();
286   string portName = inputPort->getName();
287   string nodeName = node->getName();
288
289   set<ComposedNode *> nodePortAncestors = node->getAllAscendanceOf();
290
291   if ( nodePortAncestors.find(this) == nodePortAncestors.end() ) 
292     {
293       string what("InputPort "); what+= portName; what+=" does not belong to node "; what += nodeName;
294       throw Exception(what);
295     }
296
297   Node *father = node;
298   while (father != this)
299     {
300       portName = father->getName() + '.' + portName;
301       father = father->_father;
302     }
303   return portName;
304 }
305
306 const string ComposedNode::getOutputPortName(const OutputPort *outputPort) throw (Exception)
307 {
308 }
309
310 /**
311  *
312  * @note : Runtime called method. Perform, the state updating, from the son node 'node' emitting the event 'event' (among Executor static const var).
313  *          WARNING Precondition : this == node->_father
314  * @return : The event (among Executor static const var) destinated to this->_father node to perform eventually up level update.
315  *
316  */
317 YACS::Event ComposedNode::updateStateFrom(Node *node,        //* I : node emitting event
318                                           YACS::Event event  //* I : event emitted
319                                           )
320 {
321   switch(event)
322     {
323     case YACS::START:
324       return updateStateOnStartEventFrom(node);
325       break;
326     case YACS::FINISH:
327       return updateStateOnFinishedEventFrom(node);
328       break;
329     default:
330       return YACS::NOEVENT;//TODO unexpected type of event
331       break;
332     }
333 }
334
335 InPort *ComposedNode::buildDelegateOf(InPort *port, const set<ComposedNode *>& pointsOfView)
336 {
337   return port;
338 }
339
340 OutPort *ComposedNode::buildDelegateOf(OutPort *port, const set<ComposedNode *>& pointsOfView)
341 {
342   return port;
343 }
344
345 InPort *ComposedNode::getDelegateOf(InPort *port, const set<ComposedNode *>& pointsOfView) throw(Exception)
346 {
347   return port;
348 }
349
350 OutPort *ComposedNode::getDelegateOf(OutPort *port, const set<ComposedNode *>& pointsOfView) throw(Exception)
351 {
352   return port;
353 }
354
355 InPort *ComposedNode::releaseDelegateOf(InPort *port, const set<ComposedNode *>& pointsOfView) throw(Exception)
356 {
357   return port;
358 }
359
360 OutPort *ComposedNode::releaseDelegateOf(OutPort *port, const set<ComposedNode *>& pointsOfView) throw(Exception)
361 {
362   return port;
363 }