]> 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/24 10:11:28 $
7   Version:   $Revision: 1.12 $
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     bbtkDebugMessage("process",5,
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     bbtkDebugMessage("process",5,
214                      "<=== Connection::BackwardUpdate() ["
215                      <<GetFullName()<<"]"<<std::endl);
216     return s;
217   }
218   //==================================================================
219
220   /*
221   //==================================================================
222   /// Forward Update
223   void Connection::ForwardUpdate()
224   {
225     bbtkDebugMessageInc("process",2,
226                         "Connection::ForwardUpdate() ["
227                         <<GetFullName()<<"]"<<std::endl);
228
229   
230     TransferData();
231
232     mTo->bbForwardUpdate(this);
233
234     bbtkDebugDecTab("process",2);
235   }
236   //==================================================================
237   */
238
239   //==================================================================
240   /// Transfers the data from the source output to the target input
241   /// doing necessary conversions (adaptation or pointer cast)
242   void Connection::TransferData()
243   {
244     bbtkDebugMessageInc("data",3,
245                         "Connection::TransferData() ["
246                         <<GetFullName()<<"]"<<std::endl);
247     
248     
249     // If an adaptor was created we need to adapt the data
250     if (mAdaptor) 
251       {
252         mAdaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
253         mAdaptor->bbExecute();
254         // LG : Connection Update does not set mTo as modified
255         mTo->bbSetInput(mInput, mAdaptor->bbGetOutput("Out"),false);
256         
257       }
258     // If no adaptor but source type is an any and target is not an any
259     else if ( mFromAny && (! mToAny) )
260       {
261         bbtkDebugMessage("data",3,
262                          " * Source type is an "
263                          <<HumanTypeName<Data>()
264                          <<" which contains a <"
265                          <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
266                          <<">"<<std::endl);
267         bbtkDebugMessage("data",3,
268                          " * Target type is <"
269                          <<HumanTypeName(mTo->bbGetInputType(mInput))
270                          <<">"<<std::endl);
271         
272         // 1) Test strict type matching between any content and target
273         if (mFrom->bbGetOutput(mOutput)
274             .contains( mTo->bbGetInputType(mInput) ) )
275           {
276             bbtkDebugMessage("data",3,
277                              " -> Equal types : transfer ok"<<std::endl);
278             mTo->bbSetInput( mInput, 
279                              mFrom->bbGetOutput(mOutput),
280                              false);
281           }
282         else 
283           {
284             // 2) Look for an adaptor
285             bbtk::BlackBox::Pointer adaptor;
286             try 
287               {
288                 adaptor = mFactory.lock()
289                   ->NewAdaptor(mFrom->bbGetOutput(mOutput).type(),
290                                mTo->bbGetInputType(mInput),
291                                "");
292               }
293             catch (...)
294               {
295               }
296             if (adaptor)  
297               {
298                 bbtkDebugMessage("data",3," -> Adaptor found : using it"
299                                  <<std::endl);
300                   adaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
301                 adaptor->bbExecute();
302                 // LG : Connection Update does not set mTo as modified
303                 mTo->bbSetInput(mInput, adaptor->bbGetOutput("Out"),false);
304                 //      adaptor->bbDelete();
305               }
306             // 3) If no adaptor found but the any content is a pointer
307             //    and target type is also a pointer : we try run-time cast
308             else if ( (mFrom->bbGetOutput(mOutput).contains_pointer()) &&
309                       (mTo->bbGetDescriptor()->GetInputDescriptor(mInput)
310                        ->IsPointerType()) )
311               {
312                 bbtkDebugMessage("data",3,
313                                  " -> No adaptor found but source and target types are both pointers : trying up or down cast"<<std::endl);
314                 
315                 void* nptr = 
316                   mFrom->bbGetOutput(mOutput)
317                   .get_pointer_to(mTo->bbGetInput(mInput).pointed_type());
318                 if (!nptr)  
319                   {
320                     bbtkError("Connection '"
321                               <<GetFullName()
322                               <<"' : <"
323                               <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
324                               <<"> to <"
325                               <<HumanTypeName(mTo->bbGetInputType(mInput))
326                               <<"> : no adaptor available and run-time up and down cast failed");
327                   }
328                 mTo->bbBruteForceSetInputPointer(mInput, nptr, false);
329               }
330             // 4) Nothing worked : error
331             else 
332               {
333                 bbtkError("Connection '"<<GetFullName()<<"' "
334                           <<"no adaptor found to convert <"
335                           <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
336                           <<"> to <"
337                           <<HumanTypeName(mTo->bbGetInputType(mInput))<<">");
338               }
339           }
340       }
341     // EO : mFromAny && ! mToAny
342     // Default case : types are the same; we use simple get-set
343     else 
344       {
345         // LG : Connection Update does not set mTo as modified
346         mTo->bbSetInput(mInput, mFrom->bbGetOutput(mOutput),false);
347       }
348
349   }
350   //==================================================================
351   
352   //==================================================================
353   /// Modified
354   void Connection::SetModifiedStatus()
355   {
356     bbtkDebugMessage("modified",2,
357                      "==> Connection::SetModifiedStatus() ["
358                      <<GetFullName()<<"]"<<std::endl);
359     
360     if (mAdaptor) mAdaptor->bbSetModifiedStatus();
361     
362     mTo->bbSetModifiedStatus(  mTo->bbGetInputConnectorMap().find(mInput)->second );
363     
364     /*
365     bbtkDebugMessage("modified",2,
366                      "==> Connection::SetModifiedStatus() ["
367                      <<GetFullName()<<"]"<<std::endl);
368     */
369   }
370   //==================================================================
371
372   
373   //==================================================================
374   std::string Connection::GetFullName() const {
375     if (mFrom && mTo) 
376       {
377         std::string res = mFrom->bbGetName()+"."+mOutput+"--"
378           +mTo->bbGetName()+"."+mInput;
379         if ((!mOriginalFrom.expired()) && (!mOriginalTo.expired()) &&
380             ((mFrom!=mOriginalFrom.lock())||(mTo!=mOriginalTo.lock())))
381           {
382             res += "("+mOriginalFrom.lock()->bbGetName()
383               +"."+mOriginalOutput+"--"
384               + mOriginalTo.lock()->bbGetName()+"."+mOriginalInput+")";
385           }
386         return res;
387       }
388     return "***Invalid Connection***";
389   }
390   //==================================================================
391
392   //==================================================================
393   void Connection::Check() const
394   {
395     bbtkMessage("debug",1,"** Checking Connection "<<(void*)this<<" ["<<GetFullName()<<"]"
396                 <<std::endl);
397     if (mFrom==0) 
398       {
399         bbtkMessage("debug",2," - From = 0"<<std::endl);
400       }
401     else
402       {
403         bbtkMessage("debug",2," - From : "<<mFrom->bbGetFullName()<<std::endl);
404         if (!mFrom->bbHasOutput(mOutput))
405           {
406             bbtkError("** Checking Connection "<<(void*)this
407                        <<" ["<<GetFullName()<<"] : "
408                       << mFrom->bbGetFullName()<<" does not have output '"
409                       <<mOutput<<"'");
410           }     
411         bbtkMessage("debug",2," - From : Output '"<<mOutput<<"' exists"<<std::endl);
412         BlackBox::OutputConnectorMapType::const_iterator i 
413           = mFrom->bbGetOutputConnectorMap().find(mOutput);
414         if (i== mFrom->bbGetOutputConnectorMap().end())
415           {
416              bbtkError("** Checking Connection "<<(void*)this
417                        <<" ["<<GetFullName()<<"] : "
418                        <<mFrom->bbGetFullName()<<" output '"
419                        <<mOutput<<"' is not in OutputConnectorMap");
420           }
421         bbtkMessage("debug",2," - From : Output '"<<mOutput
422                     <<"' is in OutputConnectorMap"<<std::endl);
423
424         std::vector< Connection* >::const_iterator j;
425         /*
426         for (j  = i->second->GetConnectionVector().begin();
427              j != i->second->GetConnectionVector().end();
428              ++j)
429           {
430             if ((*j)==this) break;
431           }
432         */
433         j = find(i->second->GetConnectionVector().begin(),
434                  i->second->GetConnectionVector().end(),
435                  this);
436        
437         if (j==i->second->GetConnectionVector().end())
438           {
439             bbtkError("** Checking Connection "<<(void*)this
440                       <<" ["<<GetFullName()<<"] : "
441                       << "Connection ["<<GetFullName()<<"] : "
442                       <<" OutputConnector '"
443                       <<mOutput<<"' of "<<mFrom->bbGetFullName()
444                       <<" does not point to this connection");
445             
446           }
447         bbtkMessage("debug",2," - From : This connection is in OutputConnector connection vector"<<std::endl);
448         bbtkMessage("debug",1," * Box from : Check successfull"<<std::endl);
449
450       }
451
452     if (mTo==0) 
453       {
454         bbtkMessage("debug",2," - To   = 0"<<std::endl);
455       }
456     else
457       {
458         bbtkMessage("debug",2," - To   : "<<mTo->bbGetName()<<std::endl);
459         //      std::cout << mTo << std::endl;
460         //      std::cout << mTo->bbGetDescriptor() << std::endl;
461         //      std::cout << mTo->bbGetDescriptor()->GetTypeName() << std::endl;
462         //      mTo->bbGetFullName();
463         bbtkMessage("debug",2," - To   : "<<mTo->bbGetFullName()<<std::endl);
464         if (!mTo->bbHasInput(mInput))
465           {
466             bbtkError("** Checking Connection "<<(void*)this
467                       <<" ["<<GetFullName()<<"] : "
468                       <<mTo->bbGetFullName()<<" does not have input '"
469                       <<mInput<<"'");
470           }     
471         bbtkMessage("debug",2," - To   : Input '"<<mInput<<"' exists"<<std::endl);
472         BlackBox::InputConnectorMapType::const_iterator i 
473           = mTo->bbGetInputConnectorMap().find(mInput);
474         if (i== mTo->bbGetInputConnectorMap().end())
475           {
476              bbtkError("** Checking Connection "<<(void*)this
477                        <<" ["<<GetFullName()<<"] : "
478                        <<mTo->bbGetFullName()<<" input '"
479                        <<mInput<<"' is not in InputConnectorMap");
480           }
481         bbtkMessage("debug",2," - To   : Input '"<<mInput
482                     <<"' is in InputConnectorMap"<<std::endl);
483
484         if (i->second->GetConnection()==0)
485           {
486             bbtkError("** Checking Connection "<<(void*)this
487                       <<" ["<<GetFullName()<<"] : "
488                       <<"Connection "<<GetFullName()<<" : "
489                       <<" InputConnector '"
490                       <<mInput<<"' of "<<mTo->bbGetFullName()
491                       <<" does not point to this connection");
492     
493           }
494         bbtkMessage("debug",2," - To   : This connection is in InputConnector connection vector"<<std::endl);
495         bbtkMessage("debug",1," * Box to   : Check successfull"<<std::endl);
496
497       }
498   }
499   //==================================================================
500  //==========================================================================
501   std::string Connection::GetObjectName() const
502   {
503     std::string s("Connection '");
504     s += GetFullName();
505     s += "'";
506     return s;
507   }
508   //==========================================================================
509   
510   //==========================================================================
511   std::string  Connection::GetObjectInfo() const 
512   {
513     std::stringstream i;
514     return i.str();
515   }
516   //==========================================================================
517
518  //==========================================================================
519 size_t  Connection::GetObjectSize() const 
520 {
521   size_t s = Superclass::GetObjectSize();
522   s += Connection::GetObjectInternalSize();
523   return s;
524   }
525   //==========================================================================
526   //==========================================================================
527 size_t  Connection::GetObjectInternalSize() const 
528 {
529   size_t s = sizeof(Connection);
530   return s;
531   }
532   //==========================================================================
533   //==========================================================================
534   size_t  Connection::GetObjectRecursiveSize() const 
535   {
536     size_t s = Superclass::GetObjectRecursiveSize();
537     s += Connection::GetObjectInternalSize();
538     return s;
539   }
540   //==========================================================================
541
542 }// namespace bbtk
543
544
545
546
547