]> 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 08:29:09 $
7   Version:   $Revision: 1.9 $
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,p);
147     to->bbConnectInput(input,p);
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     mOriginalFrom.reset();
172     mOriginalTo.reset();
173     if (mFrom!=0) 
174       {
175         mFrom->bbDisconnectOutput(mOutput,
176                                   GetThisPointer<Connection>());
177       }
178     else 
179       {
180         bbtkInternalError("Connection::~Connection() : invalid initial box pointer");
181       }
182     if (mTo!=0) 
183       {
184         mTo->bbDisconnectInput(mInput,
185                                GetThisPointer<Connection>());
186       }
187     else 
188       {
189         bbtkInternalError("Connection::~Connection() : invalid final box pointer");
190       }
191    mFrom.reset();
192     mTo.reset();
193
194     bbtkDebugMessage("object",2,
195                      "<== Connection::~Connection() ["
196                      <<GetFullName()<<"]"<<std::endl);
197   }
198   //==================================================================
199   
200   //==================================================================
201   /// Backward Update
202   IOStatus Connection::BackwardUpdate()
203   {
204     bbtkDebugMessageInc("Process",2,
205                         "Connection::BackwardUpdate() ["
206                         <<GetFullName()<<"]"<<std::endl);
207
208     IOStatus s = UPTODATE;
209     s = mFrom->bbBackwardUpdate(GetThisPointer<Connection>());
210
211     TransferData();
212
213     if (mAdaptor && (s==MODIFIED)) mAdaptor->bbSetModifiedStatus();
214
215     bbtkDebugDecTab("Process",2);
216
217     return s;
218   }
219   //==================================================================
220
221   /*
222   //==================================================================
223   /// Forward Update
224   void Connection::ForwardUpdate()
225   {
226     bbtkDebugMessageInc("Process",2,
227                         "Connection::ForwardUpdate() ["
228                         <<GetFullName()<<"]"<<std::endl);
229
230   
231     TransferData();
232
233     mTo->bbForwardUpdate(this);
234
235     bbtkDebugDecTab("Process",2);
236   }
237   //==================================================================
238   */
239
240   //==================================================================
241   /// Transfers the data from the source output to the target input
242   /// doing necessary conversions (adaptation or pointer cast)
243   void Connection::TransferData()
244   {
245     bbtkDebugMessageInc("Process",3,
246                         "Connection::TransferData() ["
247                         <<GetFullName()<<"]"<<std::endl);
248     
249     
250     // If an adaptor was created we need to adapt the data
251     if (mAdaptor) 
252       {
253         mAdaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
254         mAdaptor->bbExecute();
255         // LG : Connection Update does not set mTo as modified
256         mTo->bbSetInput(mInput, mAdaptor->bbGetOutput("Out"),false);
257         
258       }
259     // If no adaptor but source type is an any and target is not an any
260     else if ( mFromAny && (! mToAny) )
261       {
262         bbtkDebugMessage("Data",3,
263                          "Connection::TransferData() ["
264                          <<GetFullName()<<"]"<<std::endl);
265         bbtkDebugMessage("Data",3,
266                          " * Source type is an "
267                          <<HumanTypeName<Data>()
268                          <<" which contains a <"
269                          <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
270                          <<">"<<std::endl);
271         bbtkDebugMessage("Data",3,
272                          " * Target type is <"
273                          <<HumanTypeName(mTo->bbGetInputType(mInput))
274                          <<">"<<std::endl);
275         
276         // 1) Test strict type matching between any content and target
277         if (mFrom->bbGetOutput(mOutput)
278             .contains( mTo->bbGetInputType(mInput) ) )
279           {
280             bbtkDebugMessage("Data",3,
281                              " -> Equal types : transfer ok"<<std::endl);
282             mTo->bbSetInput( mInput, 
283                              mFrom->bbGetOutput(mOutput),
284                              false);
285           }
286         else 
287           {
288             // 2) Look for an adaptor
289             bbtk::BlackBox::Pointer adaptor;
290             try 
291               {
292                 adaptor = mFactory.lock()
293                   ->NewAdaptor(mFrom->bbGetOutput(mOutput).type(),
294                                mTo->bbGetInputType(mInput),
295                                "");
296               }
297             catch (...)
298               {
299               }
300             if (adaptor)  
301               {
302                 bbtkDebugMessage("Data",3," -> Adaptor found : using it"
303                                  <<std::endl);
304                   adaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
305                 adaptor->bbExecute();
306                 // LG : Connection Update does not set mTo as modified
307                 mTo->bbSetInput(mInput, adaptor->bbGetOutput("Out"),false);
308                 //      adaptor->bbDelete();
309               }
310             // 3) If no adaptor found but the any content is a pointer
311             //    and target type is also a pointer : we try run-time cast
312             else if ( (mFrom->bbGetOutput(mOutput).contains_pointer()) &&
313                       (mTo->bbGetDescriptor()->GetInputDescriptor(mInput)
314                        ->IsPointerType()) )
315               {
316                 bbtkDebugMessage("Data",3,
317                                  " -> No adaptor found but source and target types are both pointers : trying up or down cast"<<std::endl);
318                 
319                 void* nptr = 
320                   mFrom->bbGetOutput(mOutput)
321                   .get_pointer_to(mTo->bbGetInput(mInput).pointed_type());
322                 if (!nptr)  
323                   {
324                     bbtkError("Connection '"
325                               <<GetFullName()
326                               <<"' : <"
327                               <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
328                               <<"> to <"
329                               <<HumanTypeName(mTo->bbGetInputType(mInput))
330                               <<"> : no adaptor available and run-time up and down cast failed");
331                   }
332                 mTo->bbBruteForceSetInputPointer(mInput, nptr, false);
333               }
334             // 4) Nothing worked : error
335             else 
336               {
337                 bbtkError("Connection '"<<GetFullName()<<"' "
338                           <<"no adaptor found to convert <"
339                           <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
340                           <<"> to <"
341                           <<HumanTypeName(mTo->bbGetInputType(mInput))<<">");
342               }
343           }
344       }
345     // EO : mFromAny && ! mToAny
346     // Default case : types are the same; we use simple get-set
347     else 
348       {
349         // LG : Connection Update does not set mTo as modified
350         mTo->bbSetInput(mInput, mFrom->bbGetOutput(mOutput),false);
351       }
352
353     bbtkDebugDecTab("Process",3);
354   }
355   //==================================================================
356   
357   //==================================================================
358   /// Modified
359   void Connection::SetModifiedStatus()
360   {
361     bbtkDebugMessageInc("Process",5,
362                         "Connection::SetModifiedStatus() ["
363                         <<GetFullName()<<"]"<<std::endl);
364     
365     if (mAdaptor) mAdaptor->bbSetModifiedStatus();
366     
367     mTo->bbSetModifiedStatus(  mTo->bbGetInputConnectorMap().find(mInput)->second );
368     
369     bbtkDebugDecTab("Process",5);
370   }
371   //==================================================================
372
373   
374   //==================================================================
375   std::string Connection::GetFullName() const {
376     if (mFrom && mTo) 
377       {
378         std::string res = mFrom->bbGetName()+"."+mOutput+"--"
379           +mTo->bbGetName()+"."+mInput;
380         if ((!mOriginalFrom.expired()) && (!mOriginalTo.expired()) &&
381             ((mFrom!=mOriginalFrom.lock())||(mTo!=mOriginalTo.lock())))
382           {
383             res += "("+mOriginalFrom.lock()->bbGetName()
384               +"."+mOriginalOutput+"--"
385               + mOriginalTo.lock()->bbGetName()+"."+mOriginalInput+")";
386           }
387         return res;
388       }
389     return "***Invalid Connection***";
390   }
391   //==================================================================
392
393   //==================================================================
394   void Connection::Check() const
395   {
396     bbtkMessage("debug",1,"** Checking Connection "<<(void*)this<<" ["<<GetFullName()<<"]"
397                 <<std::endl);
398     if (mFrom==0) 
399       {
400         bbtkMessage("debug",2," - From = 0"<<std::endl);
401       }
402     else
403       {
404         bbtkMessage("debug",2," - From : "<<mFrom->bbGetFullName()<<std::endl);
405         if (!mFrom->bbHasOutput(mOutput))
406           {
407             bbtkError("** Checking Connection "<<(void*)this
408                        <<" ["<<GetFullName()<<"] : "
409                       << mFrom->bbGetFullName()<<" does not have output '"
410                       <<mOutput<<"'");
411           }     
412         bbtkMessage("debug",2," - From : Output '"<<mOutput<<"' exists"<<std::endl);
413         BlackBox::OutputConnectorMapType::const_iterator i 
414           = mFrom->bbGetOutputConnectorMap().find(mOutput);
415         if (i== mFrom->bbGetOutputConnectorMap().end())
416           {
417              bbtkError("** Checking Connection "<<(void*)this
418                        <<" ["<<GetFullName()<<"] : "
419                        <<mFrom->bbGetFullName()<<" output '"
420                        <<mOutput<<"' is not in OutputConnectorMap");
421           }
422         bbtkMessage("debug",2," - From : Output '"<<mOutput
423                     <<"' is in OutputConnectorMap"<<std::endl);
424
425         std::vector< Connection::WeakPointer >::const_iterator j;
426         for (j  = i->second->GetConnectionVector().begin();
427              j != i->second->GetConnectionVector().end();
428              ++j)
429           {
430             if ((*j).lock()==GetThisPointer<Connection>()) break;
431           }
432         /*
433         j = find(i->second->GetConnectionVector().begin(),
434                  i->second->GetConnectionVector().end(),
435                  GetThisPointer<Connection>());
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