]> Creatis software - bbtk.git/blob - kernel/src/bbtkConnection.cxx
*** empty log message ***
[bbtk.git] / kernel / src / bbtkConnection.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   bbtk
4   Module:    $RCSfile: bbtkConnection.cxx,v $
5   Language:  C++
6   Date:      $Date: 2008/04/22 14:30:25 $
7   Version:   $Revision: 1.10 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See doc/license.txt or
11   http://www.creatis.insa-lyon.fr/Public/bbtk/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18 /**
19  *\file
20  *\brief Class bbtk::Connection
21  */
22
23 #include "bbtkConnection.h"
24 #include "bbtkFactory.h"
25 #include "bbtkBlackBox.h"
26 #include "bbtkMessageManager.h"
27
28 namespace bbtk
29 {
30   Connection::Pointer Connection::New(BlackBox::Pointer from, 
31                                       const std::string& output,
32                                       BlackBox::Pointer to, 
33                                       const std::string& input ,
34                                       const Factory::Pointer f  )
35   {
36     bbtkDebugMessage("object",1,"##> Connection::Connection(\""
37                      <<from->bbGetName()<<"\",\""<<output<<"\",\""
38                      <<to->bbGetName()<<"\",\""<<input<<"\")"
39                      <<std::endl);
40     Connection::Pointer p = 
41       MakePointer(new Connection(from,output,to,input,f));
42     bbtkDebugMessage("object",1,"<## Connection::Connection(\""
43                      <<from->bbGetName()<<"\",\""<<output<<"\",\""
44                      <<to->bbGetName()<<"\",\""<<input<<"\")"
45                      <<std::endl);
46     return p;
47   }
48
49   //==================================================================
50   /// Ctor with the black box from and to and their input and output.
51 /// Check the input and output compatibility
52 Connection::Connection(BlackBox::Pointer from, const std::string& output,
53                        BlackBox::Pointer to, const std::string& input ,
54                        const Factory::Pointer f  )
55     : mAdaptor(),
56       mFactory(f),
57       mFromAny(false),
58       mToAny(false)
59   {
60     bbtkDebugMessage("object",2,"==> Connection::Connection(\""
61                      <<from->bbGetName()<<"\",\""<<output<<"\",\""
62                      <<to->bbGetName()<<"\",\""<<input<<"\")"
63                      <<std::endl);    
64
65     bbtkDebugMessage("connection",1,"==> Connection::Connection(\""
66                      <<from->bbGetFullName()<<"\",\""<<output<<"\",\""
67                      <<to->bbGetFullName()<<"\",\""<<input<<"\")"
68                      <<std::endl);    
69
70     
71
72     if (! from->bbHasOutput(output) )
73       {
74         bbtkError("The box \""<<from->bbGetTypeName()<<
75                   "\" has no output \""<<output<<"\"");
76       }
77     if (! to->bbHasInput(input) )
78       {
79         bbtkError("The box \""<<to->bbGetTypeName()<<
80                   "\" has no input \""<<input<<"\"");
81       } 
82
83     if (to->bbGetInputConnectorMap().find(input)->second->IsConnected())
84       {
85         bbtkError("The input \""<<input<<"\" of the box \""<<to->bbGetName()
86                   <<"\" is already connected");
87       }
88     
89     //  std::string t1 ( from->bbGetOutputType(output).name() );
90     //   std::string t2 ( to->bbGetInputType(input).name() );
91     // if  //( t1 != t2 ) 
92     if ( from->bbGetOutputType(output) !=
93          to->bbGetInputType(input) )
94       {
95         if ( from->bbGetOutputType(output) == typeid(Data) )
96           {
97             bbtkWarning("Connection '"
98                         <<GetFullName()
99                         <<"' : '"<<from->bbGetName()<<"."<<output
100                         <<"' is of type <"
101                         <<HumanTypeName<Data>()
102                         <<"> : type compatibility with '"
103                         <<to->bbGetName()<<"."<<input
104                         <<"' will be resolved at run time"
105                         );
106             mFromAny = true;
107           }
108         else if (  to->bbGetInputType(input) == typeid(Data) )
109           {   
110             bbtkDebugMessage("Kernel",8," -> '"<<input<<"' type is "
111                              <<TypeName<Data>()<<" : can receive any data"
112                              <<std::endl);
113             mToAny = true;
114           }
115         else 
116           {
117             //   std::cout << "Adaptive connection "<<std::endl;
118             std::string name;
119             name = from->bbGetName() + "." + output + "-" 
120               + to->bbGetName() + "." + input; 
121             mAdaptor = mFactory.lock()
122               ->NewAdaptor(from->bbGetOutputType(output),
123                            to->bbGetInputType(input),
124                            name);
125             if (!mAdaptor)  
126               {  
127                 bbtkError("did not find any <"
128                           <<TypeName(from->bbGetOutputType(output))
129                           <<"> to <"
130                           <<TypeName(to->bbGetInputType(input))
131                           <<"> adaptor");
132               } 
133           }
134       }
135
136
137     mFrom = from;
138     mOriginalFrom = from;
139     mTo = to;
140     mOriginalTo = to;
141     mInput = mOriginalInput = input;
142     mOutput = mOriginalOutput = output;
143
144      // Lock this pointer !!!
145     //Pointer p = MakePointer(this,true);
146     from->bbConnectOutput(output,this);
147     to->bbConnectInput(input,this);
148
149     
150     bbtkDebugMessage("connection",1,"<== Connection::Connection(\""
151                      <<from->bbGetFullName()<<"\",\""<<output<<"\",\""
152                      <<to->bbGetFullName()<<"\",\""<<input<<"\")"
153                      <<std::endl);    
154
155     bbtkDebugMessage("object",2,"==> Connection::Connection(\""
156                      <<from->bbGetName()<<"\",\""<<output<<"\",\""
157                      <<to->bbGetName()<<"\",\""<<input<<"\")"
158                      <<std::endl);    
159   }
160  //==================================================================
161  
162   //==================================================================
163   /// Dtor 
164   Connection::~Connection()
165   {
166     bbtkDebugMessage("object",2,
167                      "==> Connection::~Connection() ["
168                      <<GetFullName()<<"]"<<std::endl);
169
170     if (mAdaptor) mAdaptor.reset();
171     if (mFrom!=0) 
172       {
173         mFrom->bbDisconnectOutput(mOutput,this);
174         //                                GetThisPointer<Connection>());
175         mFrom.reset();
176       }
177     else 
178       {
179         bbtkInternalError("Connection::~Connection() : invalid initial box pointer");
180       }
181     if (mTo!=0) 
182       {
183         mTo->bbDisconnectInput(mInput,this);//   GetThisPointer<Connection>());
184         mTo.reset();
185       }
186     else 
187       {
188         bbtkInternalError("Connection::~Connection() : invalid final box pointer");
189       }
190
191
192     bbtkDebugMessage("object",2,
193                      "<== Connection::~Connection() ["
194                      <<GetFullName()<<"]"<<std::endl);
195   }
196   //==================================================================
197   
198   //==================================================================
199   /// Backward Update
200   IOStatus Connection::BackwardUpdate()
201   {
202     bbtkDebugMessageInc("Process",2,
203                         "Connection::BackwardUpdate() ["
204                         <<GetFullName()<<"]"<<std::endl);
205
206     IOStatus s = UPTODATE;
207     s = mFrom->bbBackwardUpdate(GetThisPointer<Connection>());
208
209     TransferData();
210
211     if (mAdaptor && (s==MODIFIED)) mAdaptor->bbSetModifiedStatus();
212
213     bbtkDebugDecTab("Process",2);
214
215     return s;
216   }
217   //==================================================================
218
219   /*
220   //==================================================================
221   /// Forward Update
222   void Connection::ForwardUpdate()
223   {
224     bbtkDebugMessageInc("Process",2,
225                         "Connection::ForwardUpdate() ["
226                         <<GetFullName()<<"]"<<std::endl);
227
228   
229     TransferData();
230
231     mTo->bbForwardUpdate(this);
232
233     bbtkDebugDecTab("Process",2);
234   }
235   //==================================================================
236   */
237
238   //==================================================================
239   /// Transfers the data from the source output to the target input
240   /// doing necessary conversions (adaptation or pointer cast)
241   void Connection::TransferData()
242   {
243     bbtkDebugMessageInc("Process",3,
244                         "Connection::TransferData() ["
245                         <<GetFullName()<<"]"<<std::endl);
246     
247     
248     // If an adaptor was created we need to adapt the data
249     if (mAdaptor) 
250       {
251         mAdaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
252         mAdaptor->bbExecute();
253         // LG : Connection Update does not set mTo as modified
254         mTo->bbSetInput(mInput, mAdaptor->bbGetOutput("Out"),false);
255         
256       }
257     // If no adaptor but source type is an any and target is not an any
258     else if ( mFromAny && (! mToAny) )
259       {
260         bbtkDebugMessage("Data",3,
261                          "Connection::TransferData() ["
262                          <<GetFullName()<<"]"<<std::endl);
263         bbtkDebugMessage("Data",3,
264                          " * Source type is an "
265                          <<HumanTypeName<Data>()
266                          <<" which contains a <"
267                          <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
268                          <<">"<<std::endl);
269         bbtkDebugMessage("Data",3,
270                          " * Target type is <"
271                          <<HumanTypeName(mTo->bbGetInputType(mInput))
272                          <<">"<<std::endl);
273         
274         // 1) Test strict type matching between any content and target
275         if (mFrom->bbGetOutput(mOutput)
276             .contains( mTo->bbGetInputType(mInput) ) )
277           {
278             bbtkDebugMessage("Data",3,
279                              " -> Equal types : transfer ok"<<std::endl);
280             mTo->bbSetInput( mInput, 
281                              mFrom->bbGetOutput(mOutput),
282                              false);
283           }
284         else 
285           {
286             // 2) Look for an adaptor
287             bbtk::BlackBox::Pointer adaptor;
288             try 
289               {
290                 adaptor = mFactory.lock()
291                   ->NewAdaptor(mFrom->bbGetOutput(mOutput).type(),
292                                mTo->bbGetInputType(mInput),
293                                "");
294               }
295             catch (...)
296               {
297               }
298             if (adaptor)  
299               {
300                 bbtkDebugMessage("Data",3," -> Adaptor found : using it"
301                                  <<std::endl);
302                   adaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
303                 adaptor->bbExecute();
304                 // LG : Connection Update does not set mTo as modified
305                 mTo->bbSetInput(mInput, adaptor->bbGetOutput("Out"),false);
306                 //      adaptor->bbDelete();
307               }
308             // 3) If no adaptor found but the any content is a pointer
309             //    and target type is also a pointer : we try run-time cast
310             else if ( (mFrom->bbGetOutput(mOutput).contains_pointer()) &&
311                       (mTo->bbGetDescriptor()->GetInputDescriptor(mInput)
312                        ->IsPointerType()) )
313               {
314                 bbtkDebugMessage("Data",3,
315                                  " -> No adaptor found but source and target types are both pointers : trying up or down cast"<<std::endl);
316                 
317                 void* nptr = 
318                   mFrom->bbGetOutput(mOutput)
319                   .get_pointer_to(mTo->bbGetInput(mInput).pointed_type());
320                 if (!nptr)  
321                   {
322                     bbtkError("Connection '"
323                               <<GetFullName()
324                               <<"' : <"
325                               <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
326                               <<"> to <"
327                               <<HumanTypeName(mTo->bbGetInputType(mInput))
328                               <<"> : no adaptor available and run-time up and down cast failed");
329                   }
330                 mTo->bbBruteForceSetInputPointer(mInput, nptr, false);
331               }
332             // 4) Nothing worked : error
333             else 
334               {
335                 bbtkError("Connection '"<<GetFullName()<<"' "
336                           <<"no adaptor found to convert <"
337                           <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
338                           <<"> to <"
339                           <<HumanTypeName(mTo->bbGetInputType(mInput))<<">");
340               }
341           }
342       }
343     // EO : mFromAny && ! mToAny
344     // Default case : types are the same; we use simple get-set
345     else 
346       {
347         // LG : Connection Update does not set mTo as modified
348         mTo->bbSetInput(mInput, mFrom->bbGetOutput(mOutput),false);
349       }
350
351     bbtkDebugDecTab("Process",3);
352   }
353   //==================================================================
354   
355   //==================================================================
356   /// Modified
357   void Connection::SetModifiedStatus()
358   {
359     bbtkDebugMessageInc("Process",5,
360                         "Connection::SetModifiedStatus() ["
361                         <<GetFullName()<<"]"<<std::endl);
362     
363     if (mAdaptor) mAdaptor->bbSetModifiedStatus();
364     
365     mTo->bbSetModifiedStatus(  mTo->bbGetInputConnectorMap().find(mInput)->second );
366     
367     bbtkDebugDecTab("Process",5);
368   }
369   //==================================================================
370
371   
372   //==================================================================
373   std::string Connection::GetFullName() const {
374     if (mFrom && mTo) 
375       {
376         std::string res = mFrom->bbGetName()+"."+mOutput+"--"
377           +mTo->bbGetName()+"."+mInput;
378         if ((!mOriginalFrom.expired()) && (!mOriginalTo.expired()) &&
379             ((mFrom!=mOriginalFrom.lock())||(mTo!=mOriginalTo.lock())))
380           {
381             res += "("+mOriginalFrom.lock()->bbGetName()
382               +"."+mOriginalOutput+"--"
383               + mOriginalTo.lock()->bbGetName()+"."+mOriginalInput+")";
384           }
385         return res;
386       }
387     return "***Invalid Connection***";
388   }
389   //==================================================================
390
391   //==================================================================
392   void Connection::Check() const
393   {
394     bbtkMessage("debug",1,"** Checking Connection "<<(void*)this<<" ["<<GetFullName()<<"]"
395                 <<std::endl);
396     if (mFrom==0) 
397       {
398         bbtkMessage("debug",2," - From = 0"<<std::endl);
399       }
400     else
401       {
402         bbtkMessage("debug",2," - From : "<<mFrom->bbGetFullName()<<std::endl);
403         if (!mFrom->bbHasOutput(mOutput))
404           {
405             bbtkError("** Checking Connection "<<(void*)this
406                        <<" ["<<GetFullName()<<"] : "
407                       << mFrom->bbGetFullName()<<" does not have output '"
408                       <<mOutput<<"'");
409           }     
410         bbtkMessage("debug",2," - From : Output '"<<mOutput<<"' exists"<<std::endl);
411         BlackBox::OutputConnectorMapType::const_iterator i 
412           = mFrom->bbGetOutputConnectorMap().find(mOutput);
413         if (i== mFrom->bbGetOutputConnectorMap().end())
414           {
415              bbtkError("** Checking Connection "<<(void*)this
416                        <<" ["<<GetFullName()<<"] : "
417                        <<mFrom->bbGetFullName()<<" output '"
418                        <<mOutput<<"' is not in OutputConnectorMap");
419           }
420         bbtkMessage("debug",2," - From : Output '"<<mOutput
421                     <<"' is in OutputConnectorMap"<<std::endl);
422
423         std::vector< Connection* >::const_iterator j;
424         /*
425         for (j  = i->second->GetConnectionVector().begin();
426              j != i->second->GetConnectionVector().end();
427              ++j)
428           {
429             if ((*j)==this) break;
430           }
431         */
432         j = find(i->second->GetConnectionVector().begin(),
433                  i->second->GetConnectionVector().end(),
434                  this);
435        
436         if (j==i->second->GetConnectionVector().end())
437           {
438             bbtkError("** Checking Connection "<<(void*)this
439                       <<" ["<<GetFullName()<<"] : "
440                       << "Connection ["<<GetFullName()<<"] : "
441                       <<" OutputConnector '"
442                       <<mOutput<<"' of "<<mFrom->bbGetFullName()
443                       <<" does not point to this connection");
444             
445           }
446         bbtkMessage("debug",2," - From : This connection is in OutputConnector connection vector"<<std::endl);
447         bbtkMessage("debug",1," * Box from : Check successfull"<<std::endl);
448
449       }
450
451     if (mTo==0) 
452       {
453         bbtkMessage("debug",2," - To   = 0"<<std::endl);
454       }
455     else
456       {
457         bbtkMessage("debug",2," - To   : "<<mTo->bbGetName()<<std::endl);
458         //      std::cout << mTo << std::endl;
459         //      std::cout << mTo->bbGetDescriptor() << std::endl;
460         //      std::cout << mTo->bbGetDescriptor()->GetTypeName() << std::endl;
461         //      mTo->bbGetFullName();
462         bbtkMessage("debug",2," - To   : "<<mTo->bbGetFullName()<<std::endl);
463         if (!mTo->bbHasInput(mInput))
464           {
465             bbtkError("** Checking Connection "<<(void*)this
466                       <<" ["<<GetFullName()<<"] : "
467                       <<mTo->bbGetFullName()<<" does not have input '"
468                       <<mInput<<"'");
469           }     
470         bbtkMessage("debug",2," - To   : Input '"<<mInput<<"' exists"<<std::endl);
471         BlackBox::InputConnectorMapType::const_iterator i 
472           = mTo->bbGetInputConnectorMap().find(mInput);
473         if (i== mTo->bbGetInputConnectorMap().end())
474           {
475              bbtkError("** Checking Connection "<<(void*)this
476                        <<" ["<<GetFullName()<<"] : "
477                        <<mTo->bbGetFullName()<<" input '"
478                        <<mInput<<"' is not in InputConnectorMap");
479           }
480         bbtkMessage("debug",2," - To   : Input '"<<mInput
481                     <<"' is in InputConnectorMap"<<std::endl);
482
483         if (i->second->GetConnection()==0)
484           {
485             bbtkError("** Checking Connection "<<(void*)this
486                       <<" ["<<GetFullName()<<"] : "
487                       <<"Connection "<<GetFullName()<<" : "
488                       <<" InputConnector '"
489                       <<mInput<<"' of "<<mTo->bbGetFullName()
490                       <<" does not point to this connection");
491     
492           }
493         bbtkMessage("debug",2," - To   : This connection is in InputConnector connection vector"<<std::endl);
494         bbtkMessage("debug",1," * Box to   : Check successfull"<<std::endl);
495
496       }
497   }
498   //==================================================================
499  //==========================================================================
500   std::string Connection::GetObjectName() const
501   {
502     std::string s("Connection '");
503     s += GetFullName();
504     s += "'";
505     return s;
506   }
507   //==========================================================================
508   
509   //==========================================================================
510   std::string  Connection::GetObjectInfo() const 
511   {
512     std::stringstream i;
513     return i.str();
514   }
515   //==========================================================================
516
517  //==========================================================================
518 size_t  Connection::GetObjectSize() const 
519 {
520   size_t s = Superclass::GetObjectSize();
521   s += Connection::GetObjectInternalSize();
522   return s;
523   }
524   //==========================================================================
525   //==========================================================================
526 size_t  Connection::GetObjectInternalSize() const 
527 {
528   size_t s = sizeof(Connection);
529   return s;
530   }
531   //==========================================================================
532   //==========================================================================
533   size_t  Connection::GetObjectRecursiveSize() const 
534   {
535     size_t s = Superclass::GetObjectRecursiveSize();
536     s += Connection::GetObjectInternalSize();
537     return s;
538   }
539   //==========================================================================
540
541 }// namespace bbtk
542
543
544
545
546