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